diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-03-12 19:15:35 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-03-12 19:15:35 -0400 |
commit | aba0eb84c87928992c021d33ef3ea59c931086b9 (patch) | |
tree | bdc323efc6773d0dcce4406ca275e9192eabb9b2 /arch/powerpc | |
parent | 7230c5644188cd9e3fb380cc97dde00c464a3ba7 (diff) | |
parent | 3780444c4fcec28c96ab7002858bb051215a5fc1 (diff) |
Merge branch 'eeh' into next
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/device.h | 3 | ||||
-rw-r--r-- | arch/powerpc/include/asm/eeh.h | 134 | ||||
-rw-r--r-- | arch/powerpc/include/asm/eeh_event.h | 33 | ||||
-rw-r--r-- | arch/powerpc/include/asm/ppc-pci.h | 89 | ||||
-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.c | 1044 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_cache.c | 44 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_dev.c | 102 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_driver.c | 213 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_event.c | 55 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_pseries.c | 565 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_sysfs.c | 25 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/msi.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci_dlpar.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 7 |
17 files changed, 1462 insertions, 869 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 66ea9b8b95c5..d60f99814ffb 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * eeh.h | ||
3 | * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. | 2 | * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. |
3 | * Copyright 2001-2012 IBM Corporation. | ||
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -31,44 +31,105 @@ struct device_node; | |||
31 | 31 | ||
32 | #ifdef CONFIG_EEH | 32 | #ifdef CONFIG_EEH |
33 | 33 | ||
34 | extern int eeh_subsystem_enabled; | 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 | } | ||
35 | 70 | ||
36 | /* Values for eeh_mode bits in device_node */ | 71 | /* |
37 | #define EEH_MODE_SUPPORTED (1<<0) | 72 | * The struct is used to trace the registered EEH operation |
38 | #define EEH_MODE_NOCHECK (1<<1) | 73 | * callback functions. Actually, those operation callback |
39 | #define EEH_MODE_ISOLATED (1<<2) | 74 | * functions are heavily platform dependent. That means the |
40 | #define EEH_MODE_RECOVERING (1<<3) | 75 | * platform should register its own EEH operation callback |
41 | #define EEH_MODE_IRQ_DISABLED (1<<4) | 76 | * functions before any EEH further operations. |
77 | */ | ||
78 | #define EEH_OPT_DISABLE 0 /* EEH disable */ | ||
79 | #define EEH_OPT_ENABLE 1 /* EEH enable */ | ||
80 | #define EEH_OPT_THAW_MMIO 2 /* MMIO enable */ | ||
81 | #define EEH_OPT_THAW_DMA 3 /* DMA enable */ | ||
82 | #define EEH_STATE_UNAVAILABLE (1 << 0) /* State unavailable */ | ||
83 | #define EEH_STATE_NOT_SUPPORT (1 << 1) /* EEH not supported */ | ||
84 | #define EEH_STATE_RESET_ACTIVE (1 << 2) /* Active reset */ | ||
85 | #define EEH_STATE_MMIO_ACTIVE (1 << 3) /* Active MMIO */ | ||
86 | #define EEH_STATE_DMA_ACTIVE (1 << 4) /* Active DMA */ | ||
87 | #define EEH_STATE_MMIO_ENABLED (1 << 5) /* MMIO enabled */ | ||
88 | #define EEH_STATE_DMA_ENABLED (1 << 6) /* DMA enabled */ | ||
89 | #define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */ | ||
90 | #define EEH_RESET_HOT 1 /* Hot reset */ | ||
91 | #define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */ | ||
92 | #define EEH_LOG_TEMP 1 /* EEH temporary error log */ | ||
93 | #define EEH_LOG_PERM 2 /* EEH permanent error log */ | ||
94 | |||
95 | struct eeh_ops { | ||
96 | char *name; | ||
97 | int (*init)(void); | ||
98 | int (*set_option)(struct device_node *dn, int option); | ||
99 | int (*get_pe_addr)(struct device_node *dn); | ||
100 | int (*get_state)(struct device_node *dn, int *state); | ||
101 | int (*reset)(struct device_node *dn, int option); | ||
102 | int (*wait_state)(struct device_node *dn, int max_wait); | ||
103 | int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len); | ||
104 | int (*configure_bridge)(struct device_node *dn); | ||
105 | int (*read_config)(struct device_node *dn, int where, int size, u32 *val); | ||
106 | int (*write_config)(struct device_node *dn, int where, int size, u32 val); | ||
107 | }; | ||
108 | |||
109 | extern struct eeh_ops *eeh_ops; | ||
110 | extern int eeh_subsystem_enabled; | ||
42 | 111 | ||
43 | /* Max number of EEH freezes allowed before we consider the device | 112 | /* |
44 | * to be permanently disabled. */ | 113 | * Max number of EEH freezes allowed before we consider the device |
114 | * to be permanently disabled. | ||
115 | */ | ||
45 | #define EEH_MAX_ALLOWED_FREEZES 5 | 116 | #define EEH_MAX_ALLOWED_FREEZES 5 |
46 | 117 | ||
118 | void * __devinit eeh_dev_init(struct device_node *dn, void *data); | ||
119 | void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb); | ||
120 | void __init eeh_dev_phb_init(void); | ||
47 | void __init eeh_init(void); | 121 | void __init eeh_init(void); |
122 | #ifdef CONFIG_PPC_PSERIES | ||
123 | int __init eeh_pseries_init(void); | ||
124 | #endif | ||
125 | int __init eeh_ops_register(struct eeh_ops *ops); | ||
126 | int __exit eeh_ops_unregister(const char *name); | ||
48 | unsigned long eeh_check_failure(const volatile void __iomem *token, | 127 | unsigned long eeh_check_failure(const volatile void __iomem *token, |
49 | unsigned long val); | 128 | unsigned long val); |
50 | int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); | 129 | int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); |
51 | void __init pci_addr_cache_build(void); | 130 | void __init pci_addr_cache_build(void); |
52 | |||
53 | /** | ||
54 | * eeh_add_device_early | ||
55 | * eeh_add_device_late | ||
56 | * | ||
57 | * Perform eeh initialization for devices added after boot. | ||
58 | * Call eeh_add_device_early before doing any i/o to the | ||
59 | * device (including config space i/o). Call eeh_add_device_late | ||
60 | * to finish the eeh setup for this device. | ||
61 | */ | ||
62 | void eeh_add_device_tree_early(struct device_node *); | 131 | void eeh_add_device_tree_early(struct device_node *); |
63 | void eeh_add_device_tree_late(struct pci_bus *); | 132 | void eeh_add_device_tree_late(struct pci_bus *); |
64 | |||
65 | /** | ||
66 | * eeh_remove_device_recursive - undo EEH for device & children. | ||
67 | * @dev: pci device to be removed | ||
68 | * | ||
69 | * As above, this removes the device; it also removes child | ||
70 | * pci devices as well. | ||
71 | */ | ||
72 | void eeh_remove_bus_device(struct pci_dev *); | 133 | void eeh_remove_bus_device(struct pci_dev *); |
73 | 134 | ||
74 | /** | 135 | /** |
@@ -87,8 +148,25 @@ void eeh_remove_bus_device(struct pci_dev *); | |||
87 | #define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8)) | 148 | #define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8)) |
88 | 149 | ||
89 | #else /* !CONFIG_EEH */ | 150 | #else /* !CONFIG_EEH */ |
151 | |||
152 | static inline void *eeh_dev_init(struct device_node *dn, void *data) | ||
153 | { | ||
154 | return NULL; | ||
155 | } | ||
156 | |||
157 | static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { } | ||
158 | |||
159 | static inline void eeh_dev_phb_init(void) { } | ||
160 | |||
90 | static inline void eeh_init(void) { } | 161 | static inline void eeh_init(void) { } |
91 | 162 | ||
163 | #ifdef CONFIG_PPC_PSERIES | ||
164 | static inline int eeh_pseries_init(void) | ||
165 | { | ||
166 | return 0; | ||
167 | } | ||
168 | #endif /* CONFIG_PPC_PSERIES */ | ||
169 | |||
92 | static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) | 170 | static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) |
93 | { | 171 | { |
94 | return val; | 172 | return val; |
diff --git a/arch/powerpc/include/asm/eeh_event.h b/arch/powerpc/include/asm/eeh_event.h index cc3cb04539ac..c68b012b7797 100644 --- a/arch/powerpc/include/asm/eeh_event.h +++ b/arch/powerpc/include/asm/eeh_event.h | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * eeh_event.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | 2 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 3 | * it under the terms of the GNU General Public License as published by |
6 | * the Free Software Foundation; either version 2 of the License, or | 4 | * the Free Software Foundation; either version 2 of the License, or |
@@ -22,32 +20,19 @@ | |||
22 | #define ASM_POWERPC_EEH_EVENT_H | 20 | #define ASM_POWERPC_EEH_EVENT_H |
23 | #ifdef __KERNEL__ | 21 | #ifdef __KERNEL__ |
24 | 22 | ||
25 | /** EEH event -- structure holding pci controller data that describes | 23 | /* |
26 | * a change in the isolation status of a PCI slot. A pointer | 24 | * structure holding pci controller data that describes a |
27 | * to this struct is passed as the data pointer in a notify callback. | 25 | * change in the isolation status of a PCI slot. A pointer |
26 | * to this struct is passed as the data pointer in a notify | ||
27 | * callback. | ||
28 | */ | 28 | */ |
29 | struct eeh_event { | 29 | struct eeh_event { |
30 | struct list_head list; | 30 | struct list_head list; /* to form event queue */ |
31 | struct device_node *dn; /* struct device node */ | 31 | struct eeh_dev *edev; /* EEH device */ |
32 | struct pci_dev *dev; /* affected device */ | ||
33 | }; | 32 | }; |
34 | 33 | ||
35 | /** | 34 | int eeh_send_failure_event(struct eeh_dev *edev); |
36 | * eeh_send_failure_event - generate a PCI error event | 35 | struct eeh_dev *handle_eeh_events(struct eeh_event *); |
37 | * @dev pci device | ||
38 | * | ||
39 | * This routine builds a PCI error event which will be delivered | ||
40 | * to all listeners on the eeh_notifier_chain. | ||
41 | * | ||
42 | * This routine can be called within an interrupt context; | ||
43 | * the actual event will be delivered in a normal context | ||
44 | * (from a workqueue). | ||
45 | */ | ||
46 | int eeh_send_failure_event (struct device_node *dn, | ||
47 | struct pci_dev *dev); | ||
48 | |||
49 | /* Main recovery function */ | ||
50 | struct pci_dn * handle_eeh_events (struct eeh_event *); | ||
51 | 36 | ||
52 | #endif /* __KERNEL__ */ | 37 | #endif /* __KERNEL__ */ |
53 | #endif /* ASM_POWERPC_EEH_EVENT_H */ | 38 | #endif /* ASM_POWERPC_EEH_EVENT_H */ |
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index 6d422979ebaf..e660b37aa7d0 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h | |||
@@ -47,92 +47,21 @@ extern int rtas_setup_phb(struct pci_controller *phb); | |||
47 | 47 | ||
48 | extern unsigned long pci_probe_only; | 48 | extern unsigned long pci_probe_only; |
49 | 49 | ||
50 | /* ---- EEH internal-use-only related routines ---- */ | ||
51 | #ifdef CONFIG_EEH | 50 | #ifdef CONFIG_EEH |
52 | 51 | ||
52 | void pci_addr_cache_build(void); | ||
53 | void pci_addr_cache_insert_device(struct pci_dev *dev); | 53 | void pci_addr_cache_insert_device(struct pci_dev *dev); |
54 | void pci_addr_cache_remove_device(struct pci_dev *dev); | 54 | void pci_addr_cache_remove_device(struct pci_dev *dev); |
55 | void pci_addr_cache_build(void); | 55 | struct pci_dev *pci_addr_cache_get_device(unsigned long addr); |
56 | struct pci_dev *pci_get_device_by_addr(unsigned long addr); | 56 | void eeh_slot_error_detail(struct eeh_dev *edev, int severity); |
57 | 57 | int eeh_pci_enable(struct eeh_dev *edev, int function); | |
58 | /** | 58 | int eeh_reset_pe(struct eeh_dev *); |
59 | * eeh_slot_error_detail -- record and EEH error condition to the log | 59 | void eeh_restore_bars(struct eeh_dev *); |
60 | * @pdn: pci device node | ||
61 | * @severity: EEH_LOG_TEMP_FAILURE or EEH_LOG_PERM_FAILURE | ||
62 | * | ||
63 | * Obtains the EEH error details from the RTAS subsystem, | ||
64 | * and then logs these details with the RTAS error log system. | ||
65 | */ | ||
66 | #define EEH_LOG_TEMP_FAILURE 1 | ||
67 | #define EEH_LOG_PERM_FAILURE 2 | ||
68 | void eeh_slot_error_detail (struct pci_dn *pdn, int severity); | ||
69 | |||
70 | /** | ||
71 | * rtas_pci_enable - enable IO transfers for this slot | ||
72 | * @pdn: pci device node | ||
73 | * @function: either EEH_THAW_MMIO or EEH_THAW_DMA | ||
74 | * | ||
75 | * Enable I/O transfers to this slot | ||
76 | */ | ||
77 | #define EEH_THAW_MMIO 2 | ||
78 | #define EEH_THAW_DMA 3 | ||
79 | int rtas_pci_enable(struct pci_dn *pdn, int function); | ||
80 | |||
81 | /** | ||
82 | * rtas_set_slot_reset -- unfreeze a frozen slot | ||
83 | * @pdn: pci device node | ||
84 | * | ||
85 | * Clear the EEH-frozen condition on a slot. This routine | ||
86 | * does this by asserting the PCI #RST line for 1/8th of | ||
87 | * a second; this routine will sleep while the adapter is | ||
88 | * being reset. | ||
89 | * | ||
90 | * Returns a non-zero value if the reset failed. | ||
91 | */ | ||
92 | int rtas_set_slot_reset (struct pci_dn *); | ||
93 | int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs); | ||
94 | |||
95 | /** | ||
96 | * eeh_restore_bars - Restore device configuration info. | ||
97 | * @pdn: pci device node | ||
98 | * | ||
99 | * A reset of a PCI device will clear out its config space. | ||
100 | * This routines will restore the config space for this | ||
101 | * device, and is children, to values previously obtained | ||
102 | * from the firmware. | ||
103 | */ | ||
104 | void eeh_restore_bars(struct pci_dn *); | ||
105 | |||
106 | /** | ||
107 | * rtas_configure_bridge -- firmware initialization of pci bridge | ||
108 | * @pdn: pci device node | ||
109 | * | ||
110 | * Ask the firmware to configure all PCI bridges devices | ||
111 | * located behind the indicated node. Required after a | ||
112 | * pci device reset. Does essentially the same hing as | ||
113 | * eeh_restore_bars, but for brdges, and lets firmware | ||
114 | * do the work. | ||
115 | */ | ||
116 | void rtas_configure_bridge(struct pci_dn *); | ||
117 | |||
118 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); | 60 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); |
119 | int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); | 61 | int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); |
120 | 62 | void eeh_mark_slot(struct device_node *dn, int mode_flag); | |
121 | /** | 63 | void eeh_clear_slot(struct device_node *dn, int mode_flag); |
122 | * eeh_mark_slot -- set mode flags for pertition endpoint | 64 | struct device_node *eeh_find_device_pe(struct device_node *dn); |
123 | * @pdn: pci device node | ||
124 | * | ||
125 | * mark and clear slots: find "partition endpoint" PE and set or | ||
126 | * clear the flags for each subnode of the PE. | ||
127 | */ | ||
128 | void eeh_mark_slot (struct device_node *dn, int mode_flag); | ||
129 | void eeh_clear_slot (struct device_node *dn, int mode_flag); | ||
130 | |||
131 | /** | ||
132 | * find_device_pe -- Find the associated "Partiationable Endpoint" PE | ||
133 | * @pdn: pci device node | ||
134 | */ | ||
135 | struct device_node * find_device_pe(struct device_node *dn); | ||
136 | 65 | ||
137 | void eeh_sysfs_add_device(struct pci_dev *pdev); | 66 | void eeh_sysfs_add_device(struct pci_dev *pdev); |
138 | void eeh_sysfs_remove_device(struct pci_dev *pdev); | 67 | void eeh_sysfs_remove_device(struct pci_dev *pdev); |
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 67b3e6e0cf3f..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 | 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.c b/arch/powerpc/platforms/pseries/eeh.c index c0b40af4ce4f..8011088392d3 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * eeh.c | ||
3 | * Copyright IBM Corporation 2001, 2005, 2006 | 2 | * Copyright IBM Corporation 2001, 2005, 2006 |
4 | * Copyright Dave Engebretsen & Todd Inglett 2001 | 3 | * Copyright Dave Engebretsen & Todd Inglett 2001 |
5 | * Copyright Linas Vepstas 2005, 2006 | 4 | * Copyright Linas Vepstas 2005, 2006 |
5 | * Copyright 2001-2012 IBM Corporation. | ||
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -22,7 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/sched.h> /* for init_mm */ | 25 | #include <linux/sched.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/list.h> | 27 | #include <linux/list.h> |
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
@@ -86,16 +86,8 @@ | |||
86 | /* Time to wait for a PCI slot to report status, in milliseconds */ | 86 | /* Time to wait for a PCI slot to report status, in milliseconds */ |
87 | #define PCI_BUS_RESET_WAIT_MSEC (60*1000) | 87 | #define PCI_BUS_RESET_WAIT_MSEC (60*1000) |
88 | 88 | ||
89 | /* RTAS tokens */ | 89 | /* Platform dependent EEH operations */ |
90 | static int ibm_set_eeh_option; | 90 | struct eeh_ops *eeh_ops = NULL; |
91 | static int ibm_set_slot_reset; | ||
92 | static int ibm_read_slot_reset_state; | ||
93 | static int ibm_read_slot_reset_state2; | ||
94 | static int ibm_slot_error_detail; | ||
95 | static int ibm_get_config_addr_info; | ||
96 | static int ibm_get_config_addr_info2; | ||
97 | static int ibm_configure_bridge; | ||
98 | static int ibm_configure_pe; | ||
99 | 91 | ||
100 | int eeh_subsystem_enabled; | 92 | int eeh_subsystem_enabled; |
101 | EXPORT_SYMBOL(eeh_subsystem_enabled); | 93 | EXPORT_SYMBOL(eeh_subsystem_enabled); |
@@ -103,14 +95,6 @@ EXPORT_SYMBOL(eeh_subsystem_enabled); | |||
103 | /* Lock to avoid races due to multiple reports of an error */ | 95 | /* Lock to avoid races due to multiple reports of an error */ |
104 | static DEFINE_RAW_SPINLOCK(confirm_error_lock); | 96 | static DEFINE_RAW_SPINLOCK(confirm_error_lock); |
105 | 97 | ||
106 | /* Buffer for reporting slot-error-detail rtas calls. Its here | ||
107 | * in BSS, and not dynamically alloced, so that it ends up in | ||
108 | * RMO where RTAS can access it. | ||
109 | */ | ||
110 | static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; | ||
111 | static DEFINE_SPINLOCK(slot_errbuf_lock); | ||
112 | static int eeh_error_buf_size; | ||
113 | |||
114 | /* Buffer for reporting pci register dumps. Its here in BSS, and | 98 | /* Buffer for reporting pci register dumps. Its here in BSS, and |
115 | * not dynamically alloced, so that it ends up in RMO where RTAS | 99 | * not dynamically alloced, so that it ends up in RMO where RTAS |
116 | * can access it. | 100 | * can access it. |
@@ -118,74 +102,50 @@ static int eeh_error_buf_size; | |||
118 | #define EEH_PCI_REGS_LOG_LEN 4096 | 102 | #define EEH_PCI_REGS_LOG_LEN 4096 |
119 | static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN]; | 103 | static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN]; |
120 | 104 | ||
121 | /* System monitoring statistics */ | 105 | /* |
122 | static unsigned long no_device; | 106 | * The struct is used to maintain the EEH global statistic |
123 | static unsigned long no_dn; | 107 | * information. Besides, the EEH global statistics will be |
124 | static unsigned long no_cfg_addr; | 108 | * exported to user space through procfs |
125 | static unsigned long ignored_check; | 109 | */ |
126 | static unsigned long total_mmio_ffs; | 110 | struct eeh_stats { |
127 | static unsigned long false_positives; | 111 | u64 no_device; /* PCI device not found */ |
128 | static unsigned long slot_resets; | 112 | u64 no_dn; /* OF node not found */ |
129 | 113 | u64 no_cfg_addr; /* Config address not found */ | |
130 | #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) | 114 | u64 ignored_check; /* EEH check skipped */ |
131 | 115 | u64 total_mmio_ffs; /* Total EEH checks */ | |
132 | /* --------------------------------------------------------------- */ | 116 | u64 false_positives; /* Unnecessary EEH checks */ |
133 | /* Below lies the EEH event infrastructure */ | 117 | u64 slot_resets; /* PE reset */ |
118 | }; | ||
134 | 119 | ||
135 | static void rtas_slot_error_detail(struct pci_dn *pdn, int severity, | 120 | static struct eeh_stats eeh_stats; |
136 | char *driver_log, size_t loglen) | ||
137 | { | ||
138 | int config_addr; | ||
139 | unsigned long flags; | ||
140 | int rc; | ||
141 | 121 | ||
142 | /* Log the error with the rtas logger */ | 122 | #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) |
143 | spin_lock_irqsave(&slot_errbuf_lock, flags); | ||
144 | memset(slot_errbuf, 0, eeh_error_buf_size); | ||
145 | |||
146 | /* Use PE configuration address, if present */ | ||
147 | config_addr = pdn->eeh_config_addr; | ||
148 | if (pdn->eeh_pe_config_addr) | ||
149 | config_addr = pdn->eeh_pe_config_addr; | ||
150 | |||
151 | rc = rtas_call(ibm_slot_error_detail, | ||
152 | 8, 1, NULL, config_addr, | ||
153 | BUID_HI(pdn->phb->buid), | ||
154 | BUID_LO(pdn->phb->buid), | ||
155 | virt_to_phys(driver_log), loglen, | ||
156 | virt_to_phys(slot_errbuf), | ||
157 | eeh_error_buf_size, | ||
158 | severity); | ||
159 | |||
160 | if (rc == 0) | ||
161 | log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); | ||
162 | spin_unlock_irqrestore(&slot_errbuf_lock, flags); | ||
163 | } | ||
164 | 123 | ||
165 | /** | 124 | /** |
166 | * gather_pci_data - copy assorted PCI config space registers to buff | 125 | * eeh_gather_pci_data - Copy assorted PCI config space registers to buff |
167 | * @pdn: device to report data for | 126 | * @edev: device to report data for |
168 | * @buf: point to buffer in which to log | 127 | * @buf: point to buffer in which to log |
169 | * @len: amount of room in buffer | 128 | * @len: amount of room in buffer |
170 | * | 129 | * |
171 | * This routine captures assorted PCI configuration space data, | 130 | * This routine captures assorted PCI configuration space data, |
172 | * and puts them into a buffer for RTAS error logging. | 131 | * and puts them into a buffer for RTAS error logging. |
173 | */ | 132 | */ |
174 | static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | 133 | static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) |
175 | { | 134 | { |
176 | struct pci_dev *dev = pdn->pcidev; | 135 | struct device_node *dn = eeh_dev_to_of_node(edev); |
136 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
177 | u32 cfg; | 137 | u32 cfg; |
178 | int cap, i; | 138 | int cap, i; |
179 | int n = 0; | 139 | int n = 0; |
180 | 140 | ||
181 | n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name); | 141 | n += scnprintf(buf+n, len-n, "%s\n", dn->full_name); |
182 | printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name); | 142 | printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name); |
183 | 143 | ||
184 | rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg); | 144 | eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg); |
185 | n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg); | 145 | n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg); |
186 | printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg); | 146 | printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg); |
187 | 147 | ||
188 | rtas_read_config(pdn, PCI_COMMAND, 4, &cfg); | 148 | eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg); |
189 | n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); | 149 | n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); |
190 | printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); | 150 | printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); |
191 | 151 | ||
@@ -196,11 +156,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
196 | 156 | ||
197 | /* Gather bridge-specific registers */ | 157 | /* Gather bridge-specific registers */ |
198 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { | 158 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { |
199 | rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg); | 159 | eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg); |
200 | n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); | 160 | n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); |
201 | printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); | 161 | printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); |
202 | 162 | ||
203 | rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg); | 163 | eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg); |
204 | n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); | 164 | n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); |
205 | printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); | 165 | printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); |
206 | } | 166 | } |
@@ -208,11 +168,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
208 | /* Dump out the PCI-X command and status regs */ | 168 | /* Dump out the PCI-X command and status regs */ |
209 | cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); | 169 | cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); |
210 | if (cap) { | 170 | if (cap) { |
211 | rtas_read_config(pdn, cap, 4, &cfg); | 171 | eeh_ops->read_config(dn, cap, 4, &cfg); |
212 | n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg); | 172 | n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg); |
213 | printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); | 173 | printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); |
214 | 174 | ||
215 | rtas_read_config(pdn, cap+4, 4, &cfg); | 175 | eeh_ops->read_config(dn, cap+4, 4, &cfg); |
216 | n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg); | 176 | n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg); |
217 | printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg); | 177 | printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg); |
218 | } | 178 | } |
@@ -225,7 +185,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
225 | "EEH: PCI-E capabilities and status follow:\n"); | 185 | "EEH: PCI-E capabilities and status follow:\n"); |
226 | 186 | ||
227 | for (i=0; i<=8; i++) { | 187 | for (i=0; i<=8; i++) { |
228 | rtas_read_config(pdn, cap+4*i, 4, &cfg); | 188 | eeh_ops->read_config(dn, cap+4*i, 4, &cfg); |
229 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); | 189 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); |
230 | printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); | 190 | printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); |
231 | } | 191 | } |
@@ -237,7 +197,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
237 | "EEH: PCI-E AER capability register set follows:\n"); | 197 | "EEH: PCI-E AER capability register set follows:\n"); |
238 | 198 | ||
239 | for (i=0; i<14; i++) { | 199 | for (i=0; i<14; i++) { |
240 | rtas_read_config(pdn, cap+4*i, 4, &cfg); | 200 | eeh_ops->read_config(dn, cap+4*i, 4, &cfg); |
241 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); | 201 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); |
242 | printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg); | 202 | printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg); |
243 | } | 203 | } |
@@ -246,111 +206,46 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
246 | 206 | ||
247 | /* Gather status on devices under the bridge */ | 207 | /* Gather status on devices under the bridge */ |
248 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { | 208 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { |
249 | struct device_node *dn; | 209 | struct device_node *child; |
250 | 210 | ||
251 | for_each_child_of_node(pdn->node, dn) { | 211 | for_each_child_of_node(dn, child) { |
252 | pdn = PCI_DN(dn); | 212 | if (of_node_to_eeh_dev(child)) |
253 | if (pdn) | 213 | n += eeh_gather_pci_data(of_node_to_eeh_dev(child), buf+n, len-n); |
254 | n += gather_pci_data(pdn, buf+n, len-n); | ||
255 | } | 214 | } |
256 | } | 215 | } |
257 | 216 | ||
258 | return n; | 217 | return n; |
259 | } | 218 | } |
260 | 219 | ||
261 | void eeh_slot_error_detail(struct pci_dn *pdn, int severity) | ||
262 | { | ||
263 | size_t loglen = 0; | ||
264 | pci_regs_buf[0] = 0; | ||
265 | |||
266 | rtas_pci_enable(pdn, EEH_THAW_MMIO); | ||
267 | rtas_configure_bridge(pdn); | ||
268 | eeh_restore_bars(pdn); | ||
269 | loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); | ||
270 | |||
271 | rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); | ||
272 | } | ||
273 | |||
274 | /** | 220 | /** |
275 | * read_slot_reset_state - Read the reset state of a device node's slot | 221 | * eeh_slot_error_detail - Generate combined log including driver log and error log |
276 | * @dn: device node to read | 222 | * @edev: device to report error log for |
277 | * @rets: array to return results in | 223 | * @severity: temporary or permanent error log |
278 | */ | ||
279 | static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) | ||
280 | { | ||
281 | int token, outputs; | ||
282 | int config_addr; | ||
283 | |||
284 | if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { | ||
285 | token = ibm_read_slot_reset_state2; | ||
286 | outputs = 4; | ||
287 | } else { | ||
288 | token = ibm_read_slot_reset_state; | ||
289 | rets[2] = 0; /* fake PE Unavailable info */ | ||
290 | outputs = 3; | ||
291 | } | ||
292 | |||
293 | /* Use PE configuration address, if present */ | ||
294 | config_addr = pdn->eeh_config_addr; | ||
295 | if (pdn->eeh_pe_config_addr) | ||
296 | config_addr = pdn->eeh_pe_config_addr; | ||
297 | |||
298 | return rtas_call(token, 3, outputs, rets, config_addr, | ||
299 | BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * eeh_wait_for_slot_status - returns error status of slot | ||
304 | * @pdn pci device node | ||
305 | * @max_wait_msecs maximum number to millisecs to wait | ||
306 | * | ||
307 | * Return negative value if a permanent error, else return | ||
308 | * Partition Endpoint (PE) status value. | ||
309 | * | 224 | * |
310 | * If @max_wait_msecs is positive, then this routine will | 225 | * This routine should be called to generate the combined log, which |
311 | * sleep until a valid status can be obtained, or until | 226 | * is comprised of driver log and error log. The driver log is figured |
312 | * the max allowed wait time is exceeded, in which case | 227 | * out from the config space of the corresponding PCI device, while |
313 | * a -2 is returned. | 228 | * the error log is fetched through platform dependent function call. |
314 | */ | 229 | */ |
315 | int | 230 | void eeh_slot_error_detail(struct eeh_dev *edev, int severity) |
316 | eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs) | ||
317 | { | 231 | { |
318 | int rc; | 232 | size_t loglen = 0; |
319 | int rets[3]; | 233 | pci_regs_buf[0] = 0; |
320 | int mwait; | ||
321 | |||
322 | while (1) { | ||
323 | rc = read_slot_reset_state(pdn, rets); | ||
324 | if (rc) return rc; | ||
325 | if (rets[1] == 0) return -1; /* EEH is not supported */ | ||
326 | |||
327 | if (rets[0] != 5) return rets[0]; /* return actual status */ | ||
328 | |||
329 | if (rets[2] == 0) return -1; /* permanently unavailable */ | ||
330 | 234 | ||
331 | if (max_wait_msecs <= 0) break; | 235 | eeh_pci_enable(edev, EEH_OPT_THAW_MMIO); |
236 | eeh_ops->configure_bridge(eeh_dev_to_of_node(edev)); | ||
237 | eeh_restore_bars(edev); | ||
238 | loglen = eeh_gather_pci_data(edev, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); | ||
332 | 239 | ||
333 | mwait = rets[2]; | 240 | eeh_ops->get_log(eeh_dev_to_of_node(edev), severity, pci_regs_buf, loglen); |
334 | if (mwait <= 0) { | ||
335 | printk (KERN_WARNING | ||
336 | "EEH: Firmware returned bad wait value=%d\n", mwait); | ||
337 | mwait = 1000; | ||
338 | } else if (mwait > 300*1000) { | ||
339 | printk (KERN_WARNING | ||
340 | "EEH: Firmware is taking too long, time=%d\n", mwait); | ||
341 | mwait = 300*1000; | ||
342 | } | ||
343 | max_wait_msecs -= mwait; | ||
344 | msleep (mwait); | ||
345 | } | ||
346 | |||
347 | printk(KERN_WARNING "EEH: Timed out waiting for slot status\n"); | ||
348 | return -2; | ||
349 | } | 241 | } |
350 | 242 | ||
351 | /** | 243 | /** |
352 | * eeh_token_to_phys - convert EEH address token to phys address | 244 | * eeh_token_to_phys - Convert EEH address token to phys address |
353 | * @token i/o token, should be address in the form 0xA.... | 245 | * @token: I/O token, should be address in the form 0xA.... |
246 | * | ||
247 | * This routine should be called to convert virtual I/O address | ||
248 | * to physical one. | ||
354 | */ | 249 | */ |
355 | static inline unsigned long eeh_token_to_phys(unsigned long token) | 250 | static inline unsigned long eeh_token_to_phys(unsigned long token) |
356 | { | 251 | { |
@@ -365,36 +260,43 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) | |||
365 | return pa | (token & (PAGE_SIZE-1)); | 260 | return pa | (token & (PAGE_SIZE-1)); |
366 | } | 261 | } |
367 | 262 | ||
368 | /** | 263 | /** |
369 | * Return the "partitionable endpoint" (pe) under which this device lies | 264 | * eeh_find_device_pe - Retrieve the PE for the given device |
265 | * @dn: device node | ||
266 | * | ||
267 | * Return the PE under which this device lies | ||
370 | */ | 268 | */ |
371 | struct device_node * find_device_pe(struct device_node *dn) | 269 | struct device_node *eeh_find_device_pe(struct device_node *dn) |
372 | { | 270 | { |
373 | while ((dn->parent) && PCI_DN(dn->parent) && | 271 | while (dn->parent && of_node_to_eeh_dev(dn->parent) && |
374 | (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { | 272 | (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { |
375 | dn = dn->parent; | 273 | dn = dn->parent; |
376 | } | 274 | } |
377 | return dn; | 275 | return dn; |
378 | } | 276 | } |
379 | 277 | ||
380 | /** Mark all devices that are children of this device as failed. | 278 | /** |
381 | * Mark the device driver too, so that it can see the failure | 279 | * __eeh_mark_slot - Mark all child devices as failed |
382 | * immediately; this is critical, since some drivers poll | 280 | * @parent: parent device |
383 | * status registers in interrupts ... If a driver is polling, | 281 | * @mode_flag: failure flag |
384 | * and the slot is frozen, then the driver can deadlock in | 282 | * |
385 | * an interrupt context, which is bad. | 283 | * Mark all devices that are children of this device as failed. |
284 | * Mark the device driver too, so that it can see the failure | ||
285 | * immediately; this is critical, since some drivers poll | ||
286 | * status registers in interrupts ... If a driver is polling, | ||
287 | * and the slot is frozen, then the driver can deadlock in | ||
288 | * an interrupt context, which is bad. | ||
386 | */ | 289 | */ |
387 | |||
388 | static void __eeh_mark_slot(struct device_node *parent, int mode_flag) | 290 | static void __eeh_mark_slot(struct device_node *parent, int mode_flag) |
389 | { | 291 | { |
390 | struct device_node *dn; | 292 | struct device_node *dn; |
391 | 293 | ||
392 | for_each_child_of_node(parent, dn) { | 294 | for_each_child_of_node(parent, dn) { |
393 | if (PCI_DN(dn)) { | 295 | if (of_node_to_eeh_dev(dn)) { |
394 | /* Mark the pci device driver too */ | 296 | /* Mark the pci device driver too */ |
395 | struct pci_dev *dev = PCI_DN(dn)->pcidev; | 297 | struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; |
396 | 298 | ||
397 | PCI_DN(dn)->eeh_mode |= mode_flag; | 299 | of_node_to_eeh_dev(dn)->mode |= mode_flag; |
398 | 300 | ||
399 | if (dev && dev->driver) | 301 | if (dev && dev->driver) |
400 | dev->error_state = pci_channel_io_frozen; | 302 | dev->error_state = pci_channel_io_frozen; |
@@ -404,92 +306,81 @@ static void __eeh_mark_slot(struct device_node *parent, int mode_flag) | |||
404 | } | 306 | } |
405 | } | 307 | } |
406 | 308 | ||
407 | void eeh_mark_slot (struct device_node *dn, int mode_flag) | 309 | /** |
310 | * eeh_mark_slot - Mark the indicated device and its children as failed | ||
311 | * @dn: parent device | ||
312 | * @mode_flag: failure flag | ||
313 | * | ||
314 | * Mark the indicated device and its child devices as failed. | ||
315 | * The device drivers are marked as failed as well. | ||
316 | */ | ||
317 | void eeh_mark_slot(struct device_node *dn, int mode_flag) | ||
408 | { | 318 | { |
409 | struct pci_dev *dev; | 319 | struct pci_dev *dev; |
410 | dn = find_device_pe (dn); | 320 | dn = eeh_find_device_pe(dn); |
411 | 321 | ||
412 | /* Back up one, since config addrs might be shared */ | 322 | /* Back up one, since config addrs might be shared */ |
413 | if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) | 323 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) |
414 | dn = dn->parent; | 324 | dn = dn->parent; |
415 | 325 | ||
416 | PCI_DN(dn)->eeh_mode |= mode_flag; | 326 | of_node_to_eeh_dev(dn)->mode |= mode_flag; |
417 | 327 | ||
418 | /* Mark the pci device too */ | 328 | /* Mark the pci device too */ |
419 | dev = PCI_DN(dn)->pcidev; | 329 | dev = of_node_to_eeh_dev(dn)->pdev; |
420 | if (dev) | 330 | if (dev) |
421 | dev->error_state = pci_channel_io_frozen; | 331 | dev->error_state = pci_channel_io_frozen; |
422 | 332 | ||
423 | __eeh_mark_slot(dn, mode_flag); | 333 | __eeh_mark_slot(dn, mode_flag); |
424 | } | 334 | } |
425 | 335 | ||
336 | /** | ||
337 | * __eeh_clear_slot - Clear failure flag for the child devices | ||
338 | * @parent: parent device | ||
339 | * @mode_flag: flag to be cleared | ||
340 | * | ||
341 | * Clear failure flag for the child devices. | ||
342 | */ | ||
426 | static void __eeh_clear_slot(struct device_node *parent, int mode_flag) | 343 | static void __eeh_clear_slot(struct device_node *parent, int mode_flag) |
427 | { | 344 | { |
428 | struct device_node *dn; | 345 | struct device_node *dn; |
429 | 346 | ||
430 | for_each_child_of_node(parent, dn) { | 347 | for_each_child_of_node(parent, dn) { |
431 | if (PCI_DN(dn)) { | 348 | if (of_node_to_eeh_dev(dn)) { |
432 | PCI_DN(dn)->eeh_mode &= ~mode_flag; | 349 | of_node_to_eeh_dev(dn)->mode &= ~mode_flag; |
433 | PCI_DN(dn)->eeh_check_count = 0; | 350 | of_node_to_eeh_dev(dn)->check_count = 0; |
434 | __eeh_clear_slot(dn, mode_flag); | 351 | __eeh_clear_slot(dn, mode_flag); |
435 | } | 352 | } |
436 | } | 353 | } |
437 | } | 354 | } |
438 | 355 | ||
439 | void eeh_clear_slot (struct device_node *dn, int mode_flag) | 356 | /** |
357 | * eeh_clear_slot - Clear failure flag for the indicated device and its children | ||
358 | * @dn: parent device | ||
359 | * @mode_flag: flag to be cleared | ||
360 | * | ||
361 | * Clear failure flag for the indicated device and its children. | ||
362 | */ | ||
363 | void eeh_clear_slot(struct device_node *dn, int mode_flag) | ||
440 | { | 364 | { |
441 | unsigned long flags; | 365 | unsigned long flags; |
442 | raw_spin_lock_irqsave(&confirm_error_lock, flags); | 366 | raw_spin_lock_irqsave(&confirm_error_lock, flags); |
443 | 367 | ||
444 | dn = find_device_pe (dn); | 368 | dn = eeh_find_device_pe(dn); |
445 | 369 | ||
446 | /* Back up one, since config addrs might be shared */ | 370 | /* Back up one, since config addrs might be shared */ |
447 | if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) | 371 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) |
448 | dn = dn->parent; | 372 | dn = dn->parent; |
449 | 373 | ||
450 | PCI_DN(dn)->eeh_mode &= ~mode_flag; | 374 | of_node_to_eeh_dev(dn)->mode &= ~mode_flag; |
451 | PCI_DN(dn)->eeh_check_count = 0; | 375 | of_node_to_eeh_dev(dn)->check_count = 0; |
452 | __eeh_clear_slot(dn, mode_flag); | 376 | __eeh_clear_slot(dn, mode_flag); |
453 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); | 377 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); |
454 | } | 378 | } |
455 | 379 | ||
456 | void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) | ||
457 | { | ||
458 | struct device_node *dn; | ||
459 | |||
460 | for_each_child_of_node(parent, dn) { | ||
461 | if (PCI_DN(dn)) { | ||
462 | |||
463 | struct pci_dev *dev = PCI_DN(dn)->pcidev; | ||
464 | |||
465 | if (dev && dev->driver) | ||
466 | *freset |= dev->needs_freset; | ||
467 | |||
468 | __eeh_set_pe_freset(dn, freset); | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | |||
473 | void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) | ||
474 | { | ||
475 | struct pci_dev *dev; | ||
476 | dn = find_device_pe(dn); | ||
477 | |||
478 | /* Back up one, since config addrs might be shared */ | ||
479 | if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) | ||
480 | dn = dn->parent; | ||
481 | |||
482 | dev = PCI_DN(dn)->pcidev; | ||
483 | if (dev) | ||
484 | *freset |= dev->needs_freset; | ||
485 | |||
486 | __eeh_set_pe_freset(dn, freset); | ||
487 | } | ||
488 | |||
489 | /** | 380 | /** |
490 | * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze | 381 | * eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze |
491 | * @dn device node | 382 | * @dn: device node |
492 | * @dev pci device, if known | 383 | * @dev: pci device, if known |
493 | * | 384 | * |
494 | * Check for an EEH failure for the given device node. Call this | 385 | * Check for an EEH failure for the given device node. Call this |
495 | * routine if the result of a read was all 0xff's and you want to | 386 | * routine if the result of a read was all 0xff's and you want to |
@@ -504,35 +395,34 @@ void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) | |||
504 | int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | 395 | int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) |
505 | { | 396 | { |
506 | int ret; | 397 | int ret; |
507 | int rets[3]; | ||
508 | unsigned long flags; | 398 | unsigned long flags; |
509 | struct pci_dn *pdn; | 399 | struct eeh_dev *edev; |
510 | int rc = 0; | 400 | int rc = 0; |
511 | const char *location; | 401 | const char *location; |
512 | 402 | ||
513 | total_mmio_ffs++; | 403 | eeh_stats.total_mmio_ffs++; |
514 | 404 | ||
515 | if (!eeh_subsystem_enabled) | 405 | if (!eeh_subsystem_enabled) |
516 | return 0; | 406 | return 0; |
517 | 407 | ||
518 | if (!dn) { | 408 | if (!dn) { |
519 | no_dn++; | 409 | eeh_stats.no_dn++; |
520 | return 0; | 410 | return 0; |
521 | } | 411 | } |
522 | dn = find_device_pe(dn); | 412 | dn = eeh_find_device_pe(dn); |
523 | pdn = PCI_DN(dn); | 413 | edev = of_node_to_eeh_dev(dn); |
524 | 414 | ||
525 | /* Access to IO BARs might get this far and still not want checking. */ | 415 | /* Access to IO BARs might get this far and still not want checking. */ |
526 | if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || | 416 | if (!(edev->mode & EEH_MODE_SUPPORTED) || |
527 | pdn->eeh_mode & EEH_MODE_NOCHECK) { | 417 | edev->mode & EEH_MODE_NOCHECK) { |
528 | ignored_check++; | 418 | eeh_stats.ignored_check++; |
529 | pr_debug("EEH: Ignored check (%x) for %s %s\n", | 419 | pr_debug("EEH: Ignored check (%x) for %s %s\n", |
530 | pdn->eeh_mode, eeh_pci_name(dev), dn->full_name); | 420 | edev->mode, eeh_pci_name(dev), dn->full_name); |
531 | return 0; | 421 | return 0; |
532 | } | 422 | } |
533 | 423 | ||
534 | if (!pdn->eeh_config_addr && !pdn->eeh_pe_config_addr) { | 424 | if (!edev->config_addr && !edev->pe_config_addr) { |
535 | no_cfg_addr++; | 425 | eeh_stats.no_cfg_addr++; |
536 | return 0; | 426 | return 0; |
537 | } | 427 | } |
538 | 428 | ||
@@ -544,15 +434,15 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
544 | */ | 434 | */ |
545 | raw_spin_lock_irqsave(&confirm_error_lock, flags); | 435 | raw_spin_lock_irqsave(&confirm_error_lock, flags); |
546 | rc = 1; | 436 | rc = 1; |
547 | if (pdn->eeh_mode & EEH_MODE_ISOLATED) { | 437 | if (edev->mode & EEH_MODE_ISOLATED) { |
548 | pdn->eeh_check_count ++; | 438 | edev->check_count++; |
549 | if (pdn->eeh_check_count % EEH_MAX_FAILS == 0) { | 439 | if (edev->check_count % EEH_MAX_FAILS == 0) { |
550 | location = of_get_property(dn, "ibm,loc-code", NULL); | 440 | location = of_get_property(dn, "ibm,loc-code", NULL); |
551 | printk (KERN_ERR "EEH: %d reads ignored for recovering device at " | 441 | printk(KERN_ERR "EEH: %d reads ignored for recovering device at " |
552 | "location=%s driver=%s pci addr=%s\n", | 442 | "location=%s driver=%s pci addr=%s\n", |
553 | pdn->eeh_check_count, location, | 443 | edev->check_count, location, |
554 | eeh_driver_name(dev), eeh_pci_name(dev)); | 444 | eeh_driver_name(dev), eeh_pci_name(dev)); |
555 | printk (KERN_ERR "EEH: Might be infinite loop in %s driver\n", | 445 | printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n", |
556 | eeh_driver_name(dev)); | 446 | eeh_driver_name(dev)); |
557 | dump_stack(); | 447 | dump_stack(); |
558 | } | 448 | } |
@@ -566,58 +456,39 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
566 | * function zero of a multi-function device. | 456 | * function zero of a multi-function device. |
567 | * In any case they must share a common PHB. | 457 | * In any case they must share a common PHB. |
568 | */ | 458 | */ |
569 | ret = read_slot_reset_state(pdn, rets); | 459 | ret = eeh_ops->get_state(dn, NULL); |
570 | |||
571 | /* If the call to firmware failed, punt */ | ||
572 | if (ret != 0) { | ||
573 | printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n", | ||
574 | ret, dn->full_name); | ||
575 | false_positives++; | ||
576 | pdn->eeh_false_positives ++; | ||
577 | rc = 0; | ||
578 | goto dn_unlock; | ||
579 | } | ||
580 | 460 | ||
581 | /* Note that config-io to empty slots may fail; | 461 | /* Note that config-io to empty slots may fail; |
582 | * they are empty when they don't have children. */ | 462 | * they are empty when they don't have children. |
583 | if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) { | 463 | * We will punt with the following conditions: Failure to get |
584 | false_positives++; | 464 | * PE's state, EEH not support and Permanently unavailable |
585 | pdn->eeh_false_positives ++; | 465 | * state, PE is in good state. |
586 | rc = 0; | 466 | */ |
587 | goto dn_unlock; | 467 | if ((ret < 0) || |
588 | } | 468 | (ret == EEH_STATE_NOT_SUPPORT) || |
589 | 469 | (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) == | |
590 | /* If EEH is not supported on this device, punt. */ | 470 | (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) { |
591 | if (rets[1] != 1) { | 471 | eeh_stats.false_positives++; |
592 | printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", | 472 | edev->false_positives ++; |
593 | ret, dn->full_name); | ||
594 | false_positives++; | ||
595 | pdn->eeh_false_positives ++; | ||
596 | rc = 0; | ||
597 | goto dn_unlock; | ||
598 | } | ||
599 | |||
600 | /* If not the kind of error we know about, punt. */ | ||
601 | if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { | ||
602 | false_positives++; | ||
603 | pdn->eeh_false_positives ++; | ||
604 | rc = 0; | 473 | rc = 0; |
605 | goto dn_unlock; | 474 | goto dn_unlock; |
606 | } | 475 | } |
607 | 476 | ||
608 | slot_resets++; | 477 | eeh_stats.slot_resets++; |
609 | 478 | ||
610 | /* Avoid repeated reports of this failure, including problems | 479 | /* Avoid repeated reports of this failure, including problems |
611 | * with other functions on this device, and functions under | 480 | * with other functions on this device, and functions under |
612 | * bridges. */ | 481 | * bridges. |
613 | eeh_mark_slot (dn, EEH_MODE_ISOLATED); | 482 | */ |
483 | eeh_mark_slot(dn, EEH_MODE_ISOLATED); | ||
614 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); | 484 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); |
615 | 485 | ||
616 | eeh_send_failure_event (dn, dev); | 486 | eeh_send_failure_event(edev); |
617 | 487 | ||
618 | /* Most EEH events are due to device driver bugs. Having | 488 | /* Most EEH events are due to device driver bugs. Having |
619 | * a stack trace will help the device-driver authors figure | 489 | * a stack trace will help the device-driver authors figure |
620 | * out what happened. So print that out. */ | 490 | * out what happened. So print that out. |
491 | */ | ||
621 | dump_stack(); | 492 | dump_stack(); |
622 | return 1; | 493 | return 1; |
623 | 494 | ||
@@ -629,9 +500,9 @@ dn_unlock: | |||
629 | EXPORT_SYMBOL_GPL(eeh_dn_check_failure); | 500 | EXPORT_SYMBOL_GPL(eeh_dn_check_failure); |
630 | 501 | ||
631 | /** | 502 | /** |
632 | * eeh_check_failure - check if all 1's data is due to EEH slot freeze | 503 | * eeh_check_failure - Check if all 1's data is due to EEH slot freeze |
633 | * @token i/o token, should be address in the form 0xA.... | 504 | * @token: I/O token, should be address in the form 0xA.... |
634 | * @val value, should be all 1's (XXX why do we need this arg??) | 505 | * @val: value, should be all 1's (XXX why do we need this arg??) |
635 | * | 506 | * |
636 | * Check for an EEH failure at the given token address. Call this | 507 | * Check for an EEH failure at the given token address. Call this |
637 | * routine if the result of a read was all 0xff's and you want to | 508 | * routine if the result of a read was all 0xff's and you want to |
@@ -648,14 +519,14 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon | |||
648 | 519 | ||
649 | /* Finding the phys addr + pci device; this is pretty quick. */ | 520 | /* Finding the phys addr + pci device; this is pretty quick. */ |
650 | addr = eeh_token_to_phys((unsigned long __force) token); | 521 | addr = eeh_token_to_phys((unsigned long __force) token); |
651 | dev = pci_get_device_by_addr(addr); | 522 | dev = pci_addr_cache_get_device(addr); |
652 | if (!dev) { | 523 | if (!dev) { |
653 | no_device++; | 524 | eeh_stats.no_device++; |
654 | return val; | 525 | return val; |
655 | } | 526 | } |
656 | 527 | ||
657 | dn = pci_device_to_OF_node(dev); | 528 | dn = pci_device_to_OF_node(dev); |
658 | eeh_dn_check_failure (dn, dev); | 529 | eeh_dn_check_failure(dn, dev); |
659 | 530 | ||
660 | pci_dev_put(dev); | 531 | pci_dev_put(dev); |
661 | return val; | 532 | return val; |
@@ -663,115 +534,54 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon | |||
663 | 534 | ||
664 | EXPORT_SYMBOL(eeh_check_failure); | 535 | EXPORT_SYMBOL(eeh_check_failure); |
665 | 536 | ||
666 | /* ------------------------------------------------------------- */ | ||
667 | /* The code below deals with error recovery */ | ||
668 | 537 | ||
669 | /** | 538 | /** |
670 | * rtas_pci_enable - enable MMIO or DMA transfers for this slot | 539 | * eeh_pci_enable - Enable MMIO or DMA transfers for this slot |
671 | * @pdn pci device node | 540 | * @edev: pci device node |
541 | * | ||
542 | * This routine should be called to reenable frozen MMIO or DMA | ||
543 | * so that it would work correctly again. It's useful while doing | ||
544 | * recovery or log collection on the indicated device. | ||
672 | */ | 545 | */ |
673 | 546 | int eeh_pci_enable(struct eeh_dev *edev, int function) | |
674 | int | ||
675 | rtas_pci_enable(struct pci_dn *pdn, int function) | ||
676 | { | 547 | { |
677 | int config_addr; | ||
678 | int rc; | 548 | int rc; |
549 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
679 | 550 | ||
680 | /* Use PE configuration address, if present */ | 551 | rc = eeh_ops->set_option(dn, function); |
681 | config_addr = pdn->eeh_config_addr; | ||
682 | if (pdn->eeh_pe_config_addr) | ||
683 | config_addr = pdn->eeh_pe_config_addr; | ||
684 | |||
685 | rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL, | ||
686 | config_addr, | ||
687 | BUID_HI(pdn->phb->buid), | ||
688 | BUID_LO(pdn->phb->buid), | ||
689 | function); | ||
690 | |||
691 | if (rc) | 552 | if (rc) |
692 | printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", | 553 | printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", |
693 | function, rc, pdn->node->full_name); | 554 | function, rc, dn->full_name); |
694 | 555 | ||
695 | rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC); | 556 | rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); |
696 | if ((rc == 4) && (function == EEH_THAW_MMIO)) | 557 | if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) && |
558 | (function == EEH_OPT_THAW_MMIO)) | ||
697 | return 0; | 559 | return 0; |
698 | 560 | ||
699 | return rc; | 561 | return rc; |
700 | } | 562 | } |
701 | 563 | ||
702 | /** | 564 | /** |
703 | * rtas_pci_slot_reset - raises/lowers the pci #RST line | ||
704 | * @pdn pci device node | ||
705 | * @state: 1/0 to raise/lower the #RST | ||
706 | * | ||
707 | * Clear the EEH-frozen condition on a slot. This routine | ||
708 | * asserts the PCI #RST line if the 'state' argument is '1', | ||
709 | * and drops the #RST line if 'state is '0'. This routine is | ||
710 | * safe to call in an interrupt context. | ||
711 | * | ||
712 | */ | ||
713 | |||
714 | static void | ||
715 | rtas_pci_slot_reset(struct pci_dn *pdn, int state) | ||
716 | { | ||
717 | int config_addr; | ||
718 | int rc; | ||
719 | |||
720 | BUG_ON (pdn==NULL); | ||
721 | |||
722 | if (!pdn->phb) { | ||
723 | printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n", | ||
724 | pdn->node->full_name); | ||
725 | return; | ||
726 | } | ||
727 | |||
728 | /* Use PE configuration address, if present */ | ||
729 | config_addr = pdn->eeh_config_addr; | ||
730 | if (pdn->eeh_pe_config_addr) | ||
731 | config_addr = pdn->eeh_pe_config_addr; | ||
732 | |||
733 | rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, | ||
734 | config_addr, | ||
735 | BUID_HI(pdn->phb->buid), | ||
736 | BUID_LO(pdn->phb->buid), | ||
737 | state); | ||
738 | |||
739 | /* Fundamental-reset not supported on this PE, try hot-reset */ | ||
740 | if (rc == -8 && state == 3) { | ||
741 | rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, | ||
742 | config_addr, | ||
743 | BUID_HI(pdn->phb->buid), | ||
744 | BUID_LO(pdn->phb->buid), 1); | ||
745 | if (rc) | ||
746 | printk(KERN_WARNING | ||
747 | "EEH: Unable to reset the failed slot," | ||
748 | " #RST=%d dn=%s\n", | ||
749 | rc, pdn->node->full_name); | ||
750 | } | ||
751 | } | ||
752 | |||
753 | /** | ||
754 | * pcibios_set_pcie_slot_reset - Set PCI-E reset state | 565 | * pcibios_set_pcie_slot_reset - Set PCI-E reset state |
755 | * @dev: pci device struct | 566 | * @dev: pci device struct |
756 | * @state: reset state to enter | 567 | * @state: reset state to enter |
757 | * | 568 | * |
758 | * Return value: | 569 | * Return value: |
759 | * 0 if success | 570 | * 0 if success |
760 | **/ | 571 | */ |
761 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) | 572 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) |
762 | { | 573 | { |
763 | struct device_node *dn = pci_device_to_OF_node(dev); | 574 | struct device_node *dn = pci_device_to_OF_node(dev); |
764 | struct pci_dn *pdn = PCI_DN(dn); | ||
765 | 575 | ||
766 | switch (state) { | 576 | switch (state) { |
767 | case pcie_deassert_reset: | 577 | case pcie_deassert_reset: |
768 | rtas_pci_slot_reset(pdn, 0); | 578 | eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); |
769 | break; | 579 | break; |
770 | case pcie_hot_reset: | 580 | case pcie_hot_reset: |
771 | rtas_pci_slot_reset(pdn, 1); | 581 | eeh_ops->reset(dn, EEH_RESET_HOT); |
772 | break; | 582 | break; |
773 | case pcie_warm_reset: | 583 | case pcie_warm_reset: |
774 | rtas_pci_slot_reset(pdn, 3); | 584 | eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); |
775 | break; | 585 | break; |
776 | default: | 586 | default: |
777 | return -EINVAL; | 587 | return -EINVAL; |
@@ -781,13 +591,66 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat | |||
781 | } | 591 | } |
782 | 592 | ||
783 | /** | 593 | /** |
784 | * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second | 594 | * __eeh_set_pe_freset - Check the required reset for child devices |
785 | * @pdn: pci device node to be reset. | 595 | * @parent: parent device |
596 | * @freset: return value | ||
597 | * | ||
598 | * Each device might have its preferred reset type: fundamental or | ||
599 | * hot reset. The routine is used to collect the information from | ||
600 | * the child devices so that they could be reset accordingly. | ||
601 | */ | ||
602 | void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) | ||
603 | { | ||
604 | struct device_node *dn; | ||
605 | |||
606 | for_each_child_of_node(parent, dn) { | ||
607 | if (of_node_to_eeh_dev(dn)) { | ||
608 | struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; | ||
609 | |||
610 | if (dev && dev->driver) | ||
611 | *freset |= dev->needs_freset; | ||
612 | |||
613 | __eeh_set_pe_freset(dn, freset); | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | |||
618 | /** | ||
619 | * eeh_set_pe_freset - Check the required reset for the indicated device and its children | ||
620 | * @dn: parent device | ||
621 | * @freset: return value | ||
622 | * | ||
623 | * Each device might have its preferred reset type: fundamental or | ||
624 | * hot reset. The routine is used to collected the information for | ||
625 | * the indicated device and its children so that the bunch of the | ||
626 | * devices could be reset properly. | ||
786 | */ | 627 | */ |
628 | void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) | ||
629 | { | ||
630 | struct pci_dev *dev; | ||
631 | dn = eeh_find_device_pe(dn); | ||
632 | |||
633 | /* Back up one, since config addrs might be shared */ | ||
634 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) | ||
635 | dn = dn->parent; | ||
636 | |||
637 | dev = of_node_to_eeh_dev(dn)->pdev; | ||
638 | if (dev) | ||
639 | *freset |= dev->needs_freset; | ||
787 | 640 | ||
788 | static void __rtas_set_slot_reset(struct pci_dn *pdn) | 641 | __eeh_set_pe_freset(dn, freset); |
642 | } | ||
643 | |||
644 | /** | ||
645 | * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second | ||
646 | * @edev: pci device node to be reset. | ||
647 | * | ||
648 | * Assert the PCI #RST line for 1/4 second. | ||
649 | */ | ||
650 | static void eeh_reset_pe_once(struct eeh_dev *edev) | ||
789 | { | 651 | { |
790 | unsigned int freset = 0; | 652 | unsigned int freset = 0; |
653 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
791 | 654 | ||
792 | /* Determine type of EEH reset required for | 655 | /* Determine type of EEH reset required for |
793 | * Partitionable Endpoint, a hot-reset (1) | 656 | * Partitionable Endpoint, a hot-reset (1) |
@@ -795,58 +658,68 @@ static void __rtas_set_slot_reset(struct pci_dn *pdn) | |||
795 | * A fundamental reset required by any device under | 658 | * A fundamental reset required by any device under |
796 | * Partitionable Endpoint trumps hot-reset. | 659 | * Partitionable Endpoint trumps hot-reset. |
797 | */ | 660 | */ |
798 | eeh_set_pe_freset(pdn->node, &freset); | 661 | eeh_set_pe_freset(dn, &freset); |
799 | 662 | ||
800 | if (freset) | 663 | if (freset) |
801 | rtas_pci_slot_reset(pdn, 3); | 664 | eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); |
802 | else | 665 | else |
803 | rtas_pci_slot_reset(pdn, 1); | 666 | eeh_ops->reset(dn, EEH_RESET_HOT); |
804 | 667 | ||
805 | /* The PCI bus requires that the reset be held high for at least | 668 | /* The PCI bus requires that the reset be held high for at least |
806 | * a 100 milliseconds. We wait a bit longer 'just in case'. */ | 669 | * a 100 milliseconds. We wait a bit longer 'just in case'. |
807 | 670 | */ | |
808 | #define PCI_BUS_RST_HOLD_TIME_MSEC 250 | 671 | #define PCI_BUS_RST_HOLD_TIME_MSEC 250 |
809 | msleep (PCI_BUS_RST_HOLD_TIME_MSEC); | 672 | msleep(PCI_BUS_RST_HOLD_TIME_MSEC); |
810 | 673 | ||
811 | /* We might get hit with another EEH freeze as soon as the | 674 | /* We might get hit with another EEH freeze as soon as the |
812 | * pci slot reset line is dropped. Make sure we don't miss | 675 | * pci slot reset line is dropped. Make sure we don't miss |
813 | * these, and clear the flag now. */ | 676 | * these, and clear the flag now. |
814 | eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED); | 677 | */ |
678 | eeh_clear_slot(dn, EEH_MODE_ISOLATED); | ||
815 | 679 | ||
816 | rtas_pci_slot_reset (pdn, 0); | 680 | eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); |
817 | 681 | ||
818 | /* After a PCI slot has been reset, the PCI Express spec requires | 682 | /* After a PCI slot has been reset, the PCI Express spec requires |
819 | * a 1.5 second idle time for the bus to stabilize, before starting | 683 | * a 1.5 second idle time for the bus to stabilize, before starting |
820 | * up traffic. */ | 684 | * up traffic. |
685 | */ | ||
821 | #define PCI_BUS_SETTLE_TIME_MSEC 1800 | 686 | #define PCI_BUS_SETTLE_TIME_MSEC 1800 |
822 | msleep (PCI_BUS_SETTLE_TIME_MSEC); | 687 | msleep(PCI_BUS_SETTLE_TIME_MSEC); |
823 | } | 688 | } |
824 | 689 | ||
825 | int rtas_set_slot_reset(struct pci_dn *pdn) | 690 | /** |
691 | * eeh_reset_pe - Reset the indicated PE | ||
692 | * @edev: PCI device associated EEH device | ||
693 | * | ||
694 | * This routine should be called to reset indicated device, including | ||
695 | * PE. A PE might include multiple PCI devices and sometimes PCI bridges | ||
696 | * might be involved as well. | ||
697 | */ | ||
698 | int eeh_reset_pe(struct eeh_dev *edev) | ||
826 | { | 699 | { |
827 | int i, rc; | 700 | int i, rc; |
701 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
828 | 702 | ||
829 | /* Take three shots at resetting the bus */ | 703 | /* Take three shots at resetting the bus */ |
830 | for (i=0; i<3; i++) { | 704 | for (i=0; i<3; i++) { |
831 | __rtas_set_slot_reset(pdn); | 705 | eeh_reset_pe_once(edev); |
832 | 706 | ||
833 | rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC); | 707 | rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); |
834 | if (rc == 0) | 708 | if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) |
835 | return 0; | 709 | return 0; |
836 | 710 | ||
837 | if (rc < 0) { | 711 | if (rc < 0) { |
838 | printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", | 712 | printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", |
839 | pdn->node->full_name); | 713 | dn->full_name); |
840 | return -1; | 714 | return -1; |
841 | } | 715 | } |
842 | printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", | 716 | printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", |
843 | i+1, pdn->node->full_name, rc); | 717 | i+1, dn->full_name, rc); |
844 | } | 718 | } |
845 | 719 | ||
846 | return -1; | 720 | return -1; |
847 | } | 721 | } |
848 | 722 | ||
849 | /* ------------------------------------------------------- */ | ||
850 | /** Save and restore of PCI BARs | 723 | /** Save and restore of PCI BARs |
851 | * | 724 | * |
852 | * Although firmware will set up BARs during boot, it doesn't | 725 | * Although firmware will set up BARs during boot, it doesn't |
@@ -856,181 +729,122 @@ int rtas_set_slot_reset(struct pci_dn *pdn) | |||
856 | */ | 729 | */ |
857 | 730 | ||
858 | /** | 731 | /** |
859 | * __restore_bars - Restore the Base Address Registers | 732 | * eeh_restore_one_device_bars - Restore the Base Address Registers for one device |
860 | * @pdn: pci device node | 733 | * @edev: PCI device associated EEH device |
861 | * | 734 | * |
862 | * Loads the PCI configuration space base address registers, | 735 | * Loads the PCI configuration space base address registers, |
863 | * the expansion ROM base address, the latency timer, and etc. | 736 | * the expansion ROM base address, the latency timer, and etc. |
864 | * from the saved values in the device node. | 737 | * from the saved values in the device node. |
865 | */ | 738 | */ |
866 | static inline void __restore_bars (struct pci_dn *pdn) | 739 | static inline void eeh_restore_one_device_bars(struct eeh_dev *edev) |
867 | { | 740 | { |
868 | int i; | 741 | int i; |
869 | u32 cmd; | 742 | u32 cmd; |
743 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
744 | |||
745 | if (!edev->phb) | ||
746 | return; | ||
870 | 747 | ||
871 | if (NULL==pdn->phb) return; | ||
872 | for (i=4; i<10; i++) { | 748 | for (i=4; i<10; i++) { |
873 | rtas_write_config(pdn, i*4, 4, pdn->config_space[i]); | 749 | eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); |
874 | } | 750 | } |
875 | 751 | ||
876 | /* 12 == Expansion ROM Address */ | 752 | /* 12 == Expansion ROM Address */ |
877 | rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]); | 753 | eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); |
878 | 754 | ||
879 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) | 755 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) |
880 | #define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)]) | 756 | #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) |
881 | 757 | ||
882 | rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1, | 758 | eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, |
883 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); | 759 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); |
884 | 760 | ||
885 | rtas_write_config (pdn, PCI_LATENCY_TIMER, 1, | 761 | eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, |
886 | SAVED_BYTE(PCI_LATENCY_TIMER)); | 762 | SAVED_BYTE(PCI_LATENCY_TIMER)); |
887 | 763 | ||
888 | /* max latency, min grant, interrupt pin and line */ | 764 | /* max latency, min grant, interrupt pin and line */ |
889 | rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]); | 765 | eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); |
890 | 766 | ||
891 | /* Restore PERR & SERR bits, some devices require it, | 767 | /* Restore PERR & SERR bits, some devices require it, |
892 | don't touch the other command bits */ | 768 | * don't touch the other command bits |
893 | rtas_read_config(pdn, PCI_COMMAND, 4, &cmd); | 769 | */ |
894 | if (pdn->config_space[1] & PCI_COMMAND_PARITY) | 770 | eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); |
771 | if (edev->config_space[1] & PCI_COMMAND_PARITY) | ||
895 | cmd |= PCI_COMMAND_PARITY; | 772 | cmd |= PCI_COMMAND_PARITY; |
896 | else | 773 | else |
897 | cmd &= ~PCI_COMMAND_PARITY; | 774 | cmd &= ~PCI_COMMAND_PARITY; |
898 | if (pdn->config_space[1] & PCI_COMMAND_SERR) | 775 | if (edev->config_space[1] & PCI_COMMAND_SERR) |
899 | cmd |= PCI_COMMAND_SERR; | 776 | cmd |= PCI_COMMAND_SERR; |
900 | else | 777 | else |
901 | cmd &= ~PCI_COMMAND_SERR; | 778 | cmd &= ~PCI_COMMAND_SERR; |
902 | rtas_write_config(pdn, PCI_COMMAND, 4, cmd); | 779 | eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); |
903 | } | 780 | } |
904 | 781 | ||
905 | /** | 782 | /** |
906 | * eeh_restore_bars - restore the PCI config space info | 783 | * eeh_restore_bars - Restore the PCI config space info |
784 | * @edev: EEH device | ||
907 | * | 785 | * |
908 | * This routine performs a recursive walk to the children | 786 | * This routine performs a recursive walk to the children |
909 | * of this device as well. | 787 | * of this device as well. |
910 | */ | 788 | */ |
911 | void eeh_restore_bars(struct pci_dn *pdn) | 789 | void eeh_restore_bars(struct eeh_dev *edev) |
912 | { | 790 | { |
913 | struct device_node *dn; | 791 | struct device_node *dn; |
914 | if (!pdn) | 792 | if (!edev) |
915 | return; | 793 | return; |
916 | 794 | ||
917 | if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code)) | 795 | if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code)) |
918 | __restore_bars (pdn); | 796 | eeh_restore_one_device_bars(edev); |
919 | 797 | ||
920 | for_each_child_of_node(pdn->node, dn) | 798 | for_each_child_of_node(eeh_dev_to_of_node(edev), dn) |
921 | eeh_restore_bars (PCI_DN(dn)); | 799 | eeh_restore_bars(of_node_to_eeh_dev(dn)); |
922 | } | 800 | } |
923 | 801 | ||
924 | /** | 802 | /** |
925 | * eeh_save_bars - save device bars | 803 | * eeh_save_bars - Save device bars |
804 | * @edev: PCI device associated EEH device | ||
926 | * | 805 | * |
927 | * Save the values of the device bars. Unlike the restore | 806 | * Save the values of the device bars. Unlike the restore |
928 | * routine, this routine is *not* recursive. This is because | 807 | * routine, this routine is *not* recursive. This is because |
929 | * PCI devices are added individually; but, for the restore, | 808 | * PCI devices are added individually; but, for the restore, |
930 | * an entire slot is reset at a time. | 809 | * an entire slot is reset at a time. |
931 | */ | 810 | */ |
932 | static void eeh_save_bars(struct pci_dn *pdn) | 811 | static void eeh_save_bars(struct eeh_dev *edev) |
933 | { | 812 | { |
934 | int i; | 813 | int i; |
814 | struct device_node *dn; | ||
935 | 815 | ||
936 | if (!pdn ) | 816 | if (!edev) |
937 | return; | 817 | return; |
818 | dn = eeh_dev_to_of_node(edev); | ||
938 | 819 | ||
939 | for (i = 0; i < 16; i++) | 820 | for (i = 0; i < 16; i++) |
940 | rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]); | 821 | eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]); |
941 | } | ||
942 | |||
943 | void | ||
944 | rtas_configure_bridge(struct pci_dn *pdn) | ||
945 | { | ||
946 | int config_addr; | ||
947 | int rc; | ||
948 | int token; | ||
949 | |||
950 | /* Use PE configuration address, if present */ | ||
951 | config_addr = pdn->eeh_config_addr; | ||
952 | if (pdn->eeh_pe_config_addr) | ||
953 | config_addr = pdn->eeh_pe_config_addr; | ||
954 | |||
955 | /* Use new configure-pe function, if supported */ | ||
956 | if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) | ||
957 | token = ibm_configure_pe; | ||
958 | else | ||
959 | token = ibm_configure_bridge; | ||
960 | |||
961 | rc = rtas_call(token, 3, 1, NULL, | ||
962 | config_addr, | ||
963 | BUID_HI(pdn->phb->buid), | ||
964 | BUID_LO(pdn->phb->buid)); | ||
965 | if (rc) { | ||
966 | printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", | ||
967 | rc, pdn->node->full_name); | ||
968 | } | ||
969 | } | 822 | } |
970 | 823 | ||
971 | /* ------------------------------------------------------------- */ | 824 | /** |
972 | /* The code below deals with enabling EEH for devices during the | 825 | * eeh_early_enable - Early enable EEH on the indicated device |
973 | * early boot sequence. EEH must be enabled before any PCI probing | 826 | * @dn: device node |
974 | * can be done. | 827 | * @data: BUID |
828 | * | ||
829 | * Enable EEH functionality on the specified PCI device. The function | ||
830 | * is expected to be called before real PCI probing is done. However, | ||
831 | * the PHBs have been initialized at this point. | ||
975 | */ | 832 | */ |
976 | 833 | static void *eeh_early_enable(struct device_node *dn, void *data) | |
977 | #define EEH_ENABLE 1 | ||
978 | |||
979 | struct eeh_early_enable_info { | ||
980 | unsigned int buid_hi; | ||
981 | unsigned int buid_lo; | ||
982 | }; | ||
983 | |||
984 | static int get_pe_addr (int config_addr, | ||
985 | struct eeh_early_enable_info *info) | ||
986 | { | 834 | { |
987 | unsigned int rets[3]; | ||
988 | int ret; | ||
989 | |||
990 | /* Use latest config-addr token on power6 */ | ||
991 | if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { | ||
992 | /* Make sure we have a PE in hand */ | ||
993 | ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, | ||
994 | config_addr, info->buid_hi, info->buid_lo, 1); | ||
995 | if (ret || (rets[0]==0)) | ||
996 | return 0; | ||
997 | |||
998 | ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, | ||
999 | config_addr, info->buid_hi, info->buid_lo, 0); | ||
1000 | if (ret) | ||
1001 | return 0; | ||
1002 | return rets[0]; | ||
1003 | } | ||
1004 | |||
1005 | /* Use older config-addr token on power5 */ | ||
1006 | if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { | ||
1007 | ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, | ||
1008 | config_addr, info->buid_hi, info->buid_lo, 0); | ||
1009 | if (ret) | ||
1010 | return 0; | ||
1011 | return rets[0]; | ||
1012 | } | ||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | /* Enable eeh for the given device node. */ | ||
1017 | static void *early_enable_eeh(struct device_node *dn, void *data) | ||
1018 | { | ||
1019 | unsigned int rets[3]; | ||
1020 | struct eeh_early_enable_info *info = data; | ||
1021 | int ret; | 835 | int ret; |
1022 | const u32 *class_code = of_get_property(dn, "class-code", NULL); | 836 | const u32 *class_code = of_get_property(dn, "class-code", NULL); |
1023 | const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); | 837 | const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); |
1024 | const u32 *device_id = of_get_property(dn, "device-id", NULL); | 838 | const u32 *device_id = of_get_property(dn, "device-id", NULL); |
1025 | const u32 *regs; | 839 | const u32 *regs; |
1026 | int enable; | 840 | int enable; |
1027 | struct pci_dn *pdn = PCI_DN(dn); | 841 | struct eeh_dev *edev = of_node_to_eeh_dev(dn); |
1028 | 842 | ||
1029 | pdn->class_code = 0; | 843 | edev->class_code = 0; |
1030 | pdn->eeh_mode = 0; | 844 | edev->mode = 0; |
1031 | pdn->eeh_check_count = 0; | 845 | edev->check_count = 0; |
1032 | pdn->eeh_freeze_count = 0; | 846 | edev->freeze_count = 0; |
1033 | pdn->eeh_false_positives = 0; | 847 | edev->false_positives = 0; |
1034 | 848 | ||
1035 | if (!of_device_is_available(dn)) | 849 | if (!of_device_is_available(dn)) |
1036 | return NULL; | 850 | return NULL; |
@@ -1041,54 +855,56 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
1041 | 855 | ||
1042 | /* There is nothing to check on PCI to ISA bridges */ | 856 | /* There is nothing to check on PCI to ISA bridges */ |
1043 | if (dn->type && !strcmp(dn->type, "isa")) { | 857 | if (dn->type && !strcmp(dn->type, "isa")) { |
1044 | pdn->eeh_mode |= EEH_MODE_NOCHECK; | 858 | edev->mode |= EEH_MODE_NOCHECK; |
1045 | return NULL; | 859 | return NULL; |
1046 | } | 860 | } |
1047 | pdn->class_code = *class_code; | 861 | edev->class_code = *class_code; |
1048 | 862 | ||
1049 | /* Ok... see if this device supports EEH. Some do, some don't, | 863 | /* Ok... see if this device supports EEH. Some do, some don't, |
1050 | * and the only way to find out is to check each and every one. */ | 864 | * and the only way to find out is to check each and every one. |
865 | */ | ||
1051 | regs = of_get_property(dn, "reg", NULL); | 866 | regs = of_get_property(dn, "reg", NULL); |
1052 | if (regs) { | 867 | if (regs) { |
1053 | /* First register entry is addr (00BBSS00) */ | 868 | /* First register entry is addr (00BBSS00) */ |
1054 | /* Try to enable eeh */ | 869 | /* Try to enable eeh */ |
1055 | ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, | 870 | ret = eeh_ops->set_option(dn, EEH_OPT_ENABLE); |
1056 | regs[0], info->buid_hi, info->buid_lo, | ||
1057 | EEH_ENABLE); | ||
1058 | 871 | ||
1059 | enable = 0; | 872 | enable = 0; |
1060 | if (ret == 0) { | 873 | if (ret == 0) { |
1061 | pdn->eeh_config_addr = regs[0]; | 874 | edev->config_addr = regs[0]; |
1062 | 875 | ||
1063 | /* If the newer, better, ibm,get-config-addr-info is supported, | 876 | /* If the newer, better, ibm,get-config-addr-info is supported, |
1064 | * then use that instead. */ | 877 | * then use that instead. |
1065 | pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info); | 878 | */ |
879 | edev->pe_config_addr = eeh_ops->get_pe_addr(dn); | ||
1066 | 880 | ||
1067 | /* Some older systems (Power4) allow the | 881 | /* Some older systems (Power4) allow the |
1068 | * ibm,set-eeh-option call to succeed even on nodes | 882 | * ibm,set-eeh-option call to succeed even on nodes |
1069 | * where EEH is not supported. Verify support | 883 | * where EEH is not supported. Verify support |
1070 | * explicitly. */ | 884 | * explicitly. |
1071 | ret = read_slot_reset_state(pdn, rets); | 885 | */ |
1072 | if ((ret == 0) && (rets[1] == 1)) | 886 | ret = eeh_ops->get_state(dn, NULL); |
887 | if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT) | ||
1073 | enable = 1; | 888 | enable = 1; |
1074 | } | 889 | } |
1075 | 890 | ||
1076 | if (enable) { | 891 | if (enable) { |
1077 | eeh_subsystem_enabled = 1; | 892 | eeh_subsystem_enabled = 1; |
1078 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; | 893 | edev->mode |= EEH_MODE_SUPPORTED; |
1079 | 894 | ||
1080 | pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", | 895 | pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", |
1081 | dn->full_name, pdn->eeh_config_addr, | 896 | dn->full_name, edev->config_addr, |
1082 | pdn->eeh_pe_config_addr); | 897 | edev->pe_config_addr); |
1083 | } else { | 898 | } else { |
1084 | 899 | ||
1085 | /* This device doesn't support EEH, but it may have an | 900 | /* This device doesn't support EEH, but it may have an |
1086 | * EEH parent, in which case we mark it as supported. */ | 901 | * EEH parent, in which case we mark it as supported. |
1087 | if (dn->parent && PCI_DN(dn->parent) | 902 | */ |
1088 | && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { | 903 | if (dn->parent && of_node_to_eeh_dev(dn->parent) && |
904 | (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { | ||
1089 | /* Parent supports EEH. */ | 905 | /* Parent supports EEH. */ |
1090 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; | 906 | edev->mode |= EEH_MODE_SUPPORTED; |
1091 | pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr; | 907 | edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr; |
1092 | return NULL; | 908 | return NULL; |
1093 | } | 909 | } |
1094 | } | 910 | } |
@@ -1097,11 +913,63 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
1097 | dn->full_name); | 913 | dn->full_name); |
1098 | } | 914 | } |
1099 | 915 | ||
1100 | eeh_save_bars(pdn); | 916 | eeh_save_bars(edev); |
1101 | return NULL; | 917 | return NULL; |
1102 | } | 918 | } |
1103 | 919 | ||
1104 | /* | 920 | /** |
921 | * eeh_ops_register - Register platform dependent EEH operations | ||
922 | * @ops: platform dependent EEH operations | ||
923 | * | ||
924 | * Register the platform dependent EEH operation callback | ||
925 | * functions. The platform should call this function before | ||
926 | * any other EEH operations. | ||
927 | */ | ||
928 | int __init eeh_ops_register(struct eeh_ops *ops) | ||
929 | { | ||
930 | if (!ops->name) { | ||
931 | pr_warning("%s: Invalid EEH ops name for %p\n", | ||
932 | __func__, ops); | ||
933 | return -EINVAL; | ||
934 | } | ||
935 | |||
936 | if (eeh_ops && eeh_ops != ops) { | ||
937 | pr_warning("%s: EEH ops of platform %s already existing (%s)\n", | ||
938 | __func__, eeh_ops->name, ops->name); | ||
939 | return -EEXIST; | ||
940 | } | ||
941 | |||
942 | eeh_ops = ops; | ||
943 | |||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | /** | ||
948 | * eeh_ops_unregister - Unreigster platform dependent EEH operations | ||
949 | * @name: name of EEH platform operations | ||
950 | * | ||
951 | * Unregister the platform dependent EEH operation callback | ||
952 | * functions. | ||
953 | */ | ||
954 | int __exit eeh_ops_unregister(const char *name) | ||
955 | { | ||
956 | if (!name || !strlen(name)) { | ||
957 | pr_warning("%s: Invalid EEH ops name\n", | ||
958 | __func__); | ||
959 | return -EINVAL; | ||
960 | } | ||
961 | |||
962 | if (eeh_ops && !strcmp(eeh_ops->name, name)) { | ||
963 | eeh_ops = NULL; | ||
964 | return 0; | ||
965 | } | ||
966 | |||
967 | return -EEXIST; | ||
968 | } | ||
969 | |||
970 | /** | ||
971 | * eeh_init - EEH initialization | ||
972 | * | ||
1105 | * Initialize EEH by trying to enable it for all of the adapters in the system. | 973 | * Initialize EEH by trying to enable it for all of the adapters in the system. |
1106 | * As a side effect we can determine here if eeh is supported at all. | 974 | * As a side effect we can determine here if eeh is supported at all. |
1107 | * Note that we leave EEH on so failed config cycles won't cause a machine | 975 | * Note that we leave EEH on so failed config cycles won't cause a machine |
@@ -1117,50 +985,35 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
1117 | void __init eeh_init(void) | 985 | void __init eeh_init(void) |
1118 | { | 986 | { |
1119 | struct device_node *phb, *np; | 987 | struct device_node *phb, *np; |
1120 | struct eeh_early_enable_info info; | 988 | int ret; |
989 | |||
990 | /* call platform initialization function */ | ||
991 | if (!eeh_ops) { | ||
992 | pr_warning("%s: Platform EEH operation not found\n", | ||
993 | __func__); | ||
994 | return; | ||
995 | } else if ((ret = eeh_ops->init())) { | ||
996 | pr_warning("%s: Failed to call platform init function (%d)\n", | ||
997 | __func__, ret); | ||
998 | return; | ||
999 | } | ||
1121 | 1000 | ||
1122 | raw_spin_lock_init(&confirm_error_lock); | 1001 | raw_spin_lock_init(&confirm_error_lock); |
1123 | spin_lock_init(&slot_errbuf_lock); | ||
1124 | 1002 | ||
1125 | np = of_find_node_by_path("/rtas"); | 1003 | np = of_find_node_by_path("/rtas"); |
1126 | if (np == NULL) | 1004 | if (np == NULL) |
1127 | return; | 1005 | return; |
1128 | 1006 | ||
1129 | ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); | ||
1130 | ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); | ||
1131 | ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); | ||
1132 | ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); | ||
1133 | ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); | ||
1134 | ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); | ||
1135 | ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); | ||
1136 | ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); | ||
1137 | ibm_configure_pe = rtas_token("ibm,configure-pe"); | ||
1138 | |||
1139 | if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) | ||
1140 | return; | ||
1141 | |||
1142 | eeh_error_buf_size = rtas_token("rtas-error-log-max"); | ||
1143 | if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { | ||
1144 | eeh_error_buf_size = 1024; | ||
1145 | } | ||
1146 | if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { | ||
1147 | printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated " | ||
1148 | "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX); | ||
1149 | eeh_error_buf_size = RTAS_ERROR_LOG_MAX; | ||
1150 | } | ||
1151 | |||
1152 | /* Enable EEH for all adapters. Note that eeh requires buid's */ | 1007 | /* Enable EEH for all adapters. Note that eeh requires buid's */ |
1153 | for (phb = of_find_node_by_name(NULL, "pci"); phb; | 1008 | for (phb = of_find_node_by_name(NULL, "pci"); phb; |
1154 | phb = of_find_node_by_name(phb, "pci")) { | 1009 | phb = of_find_node_by_name(phb, "pci")) { |
1155 | unsigned long buid; | 1010 | unsigned long buid; |
1156 | 1011 | ||
1157 | buid = get_phb_buid(phb); | 1012 | buid = get_phb_buid(phb); |
1158 | if (buid == 0 || PCI_DN(phb) == NULL) | 1013 | if (buid == 0 || !of_node_to_eeh_dev(phb)) |
1159 | continue; | 1014 | continue; |
1160 | 1015 | ||
1161 | info.buid_lo = BUID_LO(buid); | 1016 | traverse_pci_devices(phb, eeh_early_enable, NULL); |
1162 | info.buid_hi = BUID_HI(buid); | ||
1163 | traverse_pci_devices(phb, early_enable_eeh, &info); | ||
1164 | } | 1017 | } |
1165 | 1018 | ||
1166 | if (eeh_subsystem_enabled) | 1019 | if (eeh_subsystem_enabled) |
@@ -1170,7 +1023,7 @@ void __init eeh_init(void) | |||
1170 | } | 1023 | } |
1171 | 1024 | ||
1172 | /** | 1025 | /** |
1173 | * eeh_add_device_early - enable EEH for the indicated device_node | 1026 | * eeh_add_device_early - Enable EEH for the indicated device_node |
1174 | * @dn: device node for which to set up EEH | 1027 | * @dn: device node for which to set up EEH |
1175 | * | 1028 | * |
1176 | * This routine must be used to perform EEH initialization for PCI | 1029 | * This routine must be used to perform EEH initialization for PCI |
@@ -1184,21 +1037,26 @@ void __init eeh_init(void) | |||
1184 | static void eeh_add_device_early(struct device_node *dn) | 1037 | static void eeh_add_device_early(struct device_node *dn) |
1185 | { | 1038 | { |
1186 | struct pci_controller *phb; | 1039 | struct pci_controller *phb; |
1187 | struct eeh_early_enable_info info; | ||
1188 | 1040 | ||
1189 | if (!dn || !PCI_DN(dn)) | 1041 | if (!dn || !of_node_to_eeh_dev(dn)) |
1190 | return; | 1042 | return; |
1191 | phb = PCI_DN(dn)->phb; | 1043 | phb = of_node_to_eeh_dev(dn)->phb; |
1192 | 1044 | ||
1193 | /* USB Bus children of PCI devices will not have BUID's */ | 1045 | /* USB Bus children of PCI devices will not have BUID's */ |
1194 | if (NULL == phb || 0 == phb->buid) | 1046 | if (NULL == phb || 0 == phb->buid) |
1195 | return; | 1047 | return; |
1196 | 1048 | ||
1197 | info.buid_hi = BUID_HI(phb->buid); | 1049 | eeh_early_enable(dn, NULL); |
1198 | info.buid_lo = BUID_LO(phb->buid); | ||
1199 | early_enable_eeh(dn, &info); | ||
1200 | } | 1050 | } |
1201 | 1051 | ||
1052 | /** | ||
1053 | * eeh_add_device_tree_early - Enable EEH for the indicated device | ||
1054 | * @dn: device node | ||
1055 | * | ||
1056 | * This routine must be used to perform EEH initialization for the | ||
1057 | * indicated PCI device that was added after system boot (e.g. | ||
1058 | * hotplug, dlpar). | ||
1059 | */ | ||
1202 | void eeh_add_device_tree_early(struct device_node *dn) | 1060 | void eeh_add_device_tree_early(struct device_node *dn) |
1203 | { | 1061 | { |
1204 | struct device_node *sib; | 1062 | struct device_node *sib; |
@@ -1210,7 +1068,7 @@ void eeh_add_device_tree_early(struct device_node *dn) | |||
1210 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); | 1068 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); |
1211 | 1069 | ||
1212 | /** | 1070 | /** |
1213 | * eeh_add_device_late - perform EEH initialization for the indicated pci device | 1071 | * eeh_add_device_late - Perform EEH initialization for the indicated pci device |
1214 | * @dev: pci device for which to set up EEH | 1072 | * @dev: pci device for which to set up EEH |
1215 | * | 1073 | * |
1216 | * This routine must be used to complete EEH initialization for PCI | 1074 | * This routine must be used to complete EEH initialization for PCI |
@@ -1219,7 +1077,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); | |||
1219 | static void eeh_add_device_late(struct pci_dev *dev) | 1077 | static void eeh_add_device_late(struct pci_dev *dev) |
1220 | { | 1078 | { |
1221 | struct device_node *dn; | 1079 | struct device_node *dn; |
1222 | struct pci_dn *pdn; | 1080 | struct eeh_dev *edev; |
1223 | 1081 | ||
1224 | if (!dev || !eeh_subsystem_enabled) | 1082 | if (!dev || !eeh_subsystem_enabled) |
1225 | return; | 1083 | return; |
@@ -1227,20 +1085,29 @@ static void eeh_add_device_late(struct pci_dev *dev) | |||
1227 | pr_debug("EEH: Adding device %s\n", pci_name(dev)); | 1085 | pr_debug("EEH: Adding device %s\n", pci_name(dev)); |
1228 | 1086 | ||
1229 | dn = pci_device_to_OF_node(dev); | 1087 | dn = pci_device_to_OF_node(dev); |
1230 | pdn = PCI_DN(dn); | 1088 | edev = pci_dev_to_eeh_dev(dev); |
1231 | if (pdn->pcidev == dev) { | 1089 | if (edev->pdev == dev) { |
1232 | pr_debug("EEH: Already referenced !\n"); | 1090 | pr_debug("EEH: Already referenced !\n"); |
1233 | return; | 1091 | return; |
1234 | } | 1092 | } |
1235 | WARN_ON(pdn->pcidev); | 1093 | WARN_ON(edev->pdev); |
1236 | 1094 | ||
1237 | pci_dev_get (dev); | 1095 | pci_dev_get(dev); |
1238 | pdn->pcidev = dev; | 1096 | edev->pdev = dev; |
1097 | dev->dev.archdata.edev = edev; | ||
1239 | 1098 | ||
1240 | pci_addr_cache_insert_device(dev); | 1099 | pci_addr_cache_insert_device(dev); |
1241 | eeh_sysfs_add_device(dev); | 1100 | eeh_sysfs_add_device(dev); |
1242 | } | 1101 | } |
1243 | 1102 | ||
1103 | /** | ||
1104 | * eeh_add_device_tree_late - Perform EEH initialization for the indicated PCI bus | ||
1105 | * @bus: PCI bus | ||
1106 | * | ||
1107 | * This routine must be used to perform EEH initialization for PCI | ||
1108 | * devices which are attached to the indicated PCI bus. The PCI bus | ||
1109 | * is added after system boot through hotplug or dlpar. | ||
1110 | */ | ||
1244 | void eeh_add_device_tree_late(struct pci_bus *bus) | 1111 | void eeh_add_device_tree_late(struct pci_bus *bus) |
1245 | { | 1112 | { |
1246 | struct pci_dev *dev; | 1113 | struct pci_dev *dev; |
@@ -1257,7 +1124,7 @@ void eeh_add_device_tree_late(struct pci_bus *bus) | |||
1257 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); | 1124 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); |
1258 | 1125 | ||
1259 | /** | 1126 | /** |
1260 | * eeh_remove_device - undo EEH setup for the indicated pci device | 1127 | * eeh_remove_device - Undo EEH setup for the indicated pci device |
1261 | * @dev: pci device to be removed | 1128 | * @dev: pci device to be removed |
1262 | * | 1129 | * |
1263 | * This routine should be called when a device is removed from | 1130 | * This routine should be called when a device is removed from |
@@ -1268,25 +1135,35 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); | |||
1268 | */ | 1135 | */ |
1269 | static void eeh_remove_device(struct pci_dev *dev) | 1136 | static void eeh_remove_device(struct pci_dev *dev) |
1270 | { | 1137 | { |
1271 | struct device_node *dn; | 1138 | struct eeh_dev *edev; |
1139 | |||
1272 | if (!dev || !eeh_subsystem_enabled) | 1140 | if (!dev || !eeh_subsystem_enabled) |
1273 | return; | 1141 | return; |
1142 | edev = pci_dev_to_eeh_dev(dev); | ||
1274 | 1143 | ||
1275 | /* Unregister the device with the EEH/PCI address search system */ | 1144 | /* Unregister the device with the EEH/PCI address search system */ |
1276 | pr_debug("EEH: Removing device %s\n", pci_name(dev)); | 1145 | pr_debug("EEH: Removing device %s\n", pci_name(dev)); |
1277 | 1146 | ||
1278 | dn = pci_device_to_OF_node(dev); | 1147 | if (!edev || !edev->pdev) { |
1279 | if (PCI_DN(dn)->pcidev == NULL) { | ||
1280 | pr_debug("EEH: Not referenced !\n"); | 1148 | pr_debug("EEH: Not referenced !\n"); |
1281 | return; | 1149 | return; |
1282 | } | 1150 | } |
1283 | PCI_DN(dn)->pcidev = NULL; | 1151 | edev->pdev = NULL; |
1284 | pci_dev_put (dev); | 1152 | dev->dev.archdata.edev = NULL; |
1153 | pci_dev_put(dev); | ||
1285 | 1154 | ||
1286 | pci_addr_cache_remove_device(dev); | 1155 | pci_addr_cache_remove_device(dev); |
1287 | eeh_sysfs_remove_device(dev); | 1156 | eeh_sysfs_remove_device(dev); |
1288 | } | 1157 | } |
1289 | 1158 | ||
1159 | /** | ||
1160 | * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device | ||
1161 | * @dev: PCI device | ||
1162 | * | ||
1163 | * This routine must be called when a device is removed from the | ||
1164 | * running system through hotplug or dlpar. The corresponding | ||
1165 | * PCI address cache will be removed. | ||
1166 | */ | ||
1290 | void eeh_remove_bus_device(struct pci_dev *dev) | 1167 | void eeh_remove_bus_device(struct pci_dev *dev) |
1291 | { | 1168 | { |
1292 | struct pci_bus *bus = dev->subordinate; | 1169 | struct pci_bus *bus = dev->subordinate; |
@@ -1305,21 +1182,24 @@ static int proc_eeh_show(struct seq_file *m, void *v) | |||
1305 | { | 1182 | { |
1306 | if (0 == eeh_subsystem_enabled) { | 1183 | if (0 == eeh_subsystem_enabled) { |
1307 | seq_printf(m, "EEH Subsystem is globally disabled\n"); | 1184 | seq_printf(m, "EEH Subsystem is globally disabled\n"); |
1308 | seq_printf(m, "eeh_total_mmio_ffs=%ld\n", total_mmio_ffs); | 1185 | seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); |
1309 | } else { | 1186 | } else { |
1310 | seq_printf(m, "EEH Subsystem is enabled\n"); | 1187 | seq_printf(m, "EEH Subsystem is enabled\n"); |
1311 | seq_printf(m, | 1188 | seq_printf(m, |
1312 | "no device=%ld\n" | 1189 | "no device=%llu\n" |
1313 | "no device node=%ld\n" | 1190 | "no device node=%llu\n" |
1314 | "no config address=%ld\n" | 1191 | "no config address=%llu\n" |
1315 | "check not wanted=%ld\n" | 1192 | "check not wanted=%llu\n" |
1316 | "eeh_total_mmio_ffs=%ld\n" | 1193 | "eeh_total_mmio_ffs=%llu\n" |
1317 | "eeh_false_positives=%ld\n" | 1194 | "eeh_false_positives=%llu\n" |
1318 | "eeh_slot_resets=%ld\n", | 1195 | "eeh_slot_resets=%llu\n", |
1319 | no_device, no_dn, no_cfg_addr, | 1196 | eeh_stats.no_device, |
1320 | ignored_check, total_mmio_ffs, | 1197 | eeh_stats.no_dn, |
1321 | false_positives, | 1198 | eeh_stats.no_cfg_addr, |
1322 | slot_resets); | 1199 | eeh_stats.ignored_check, |
1200 | eeh_stats.total_mmio_ffs, | ||
1201 | eeh_stats.false_positives, | ||
1202 | eeh_stats.slot_resets); | ||
1323 | } | 1203 | } |
1324 | 1204 | ||
1325 | return 0; | 1205 | return 0; |
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index fc5ae767989e..e5ae1c687c66 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * eeh_cache.c | ||
3 | * PCI address cache; allows the lookup of PCI devices based on I/O address | 2 | * PCI address cache; allows the lookup of PCI devices based on I/O address |
4 | * | 3 | * |
5 | * Copyright IBM Corporation 2004 | 4 | * Copyright IBM Corporation 2004 |
@@ -47,8 +46,7 @@ | |||
47 | * than any hash algo I could think of for this problem, even | 46 | * than any hash algo I could think of for this problem, even |
48 | * with the penalty of slow pointer chases for d-cache misses). | 47 | * with the penalty of slow pointer chases for d-cache misses). |
49 | */ | 48 | */ |
50 | struct pci_io_addr_range | 49 | struct pci_io_addr_range { |
51 | { | ||
52 | struct rb_node rb_node; | 50 | struct rb_node rb_node; |
53 | unsigned long addr_lo; | 51 | unsigned long addr_lo; |
54 | unsigned long addr_hi; | 52 | unsigned long addr_hi; |
@@ -56,13 +54,12 @@ struct pci_io_addr_range | |||
56 | unsigned int flags; | 54 | unsigned int flags; |
57 | }; | 55 | }; |
58 | 56 | ||
59 | static struct pci_io_addr_cache | 57 | static struct pci_io_addr_cache { |
60 | { | ||
61 | struct rb_root rb_root; | 58 | struct rb_root rb_root; |
62 | spinlock_t piar_lock; | 59 | spinlock_t piar_lock; |
63 | } pci_io_addr_cache_root; | 60 | } pci_io_addr_cache_root; |
64 | 61 | ||
65 | static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) | 62 | static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) |
66 | { | 63 | { |
67 | struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; | 64 | struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; |
68 | 65 | ||
@@ -86,7 +83,7 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) | |||
86 | } | 83 | } |
87 | 84 | ||
88 | /** | 85 | /** |
89 | * pci_get_device_by_addr - Get device, given only address | 86 | * pci_addr_cache_get_device - Get device, given only address |
90 | * @addr: mmio (PIO) phys address or i/o port number | 87 | * @addr: mmio (PIO) phys address or i/o port number |
91 | * | 88 | * |
92 | * Given an mmio phys address, or a port number, find a pci device | 89 | * Given an mmio phys address, or a port number, find a pci device |
@@ -95,13 +92,13 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) | |||
95 | * from zero (that is, they do *not* have pci_io_addr added in). | 92 | * from zero (that is, they do *not* have pci_io_addr added in). |
96 | * It is safe to call this function within an interrupt. | 93 | * It is safe to call this function within an interrupt. |
97 | */ | 94 | */ |
98 | struct pci_dev *pci_get_device_by_addr(unsigned long addr) | 95 | struct pci_dev *pci_addr_cache_get_device(unsigned long addr) |
99 | { | 96 | { |
100 | struct pci_dev *dev; | 97 | struct pci_dev *dev; |
101 | unsigned long flags; | 98 | unsigned long flags; |
102 | 99 | ||
103 | spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); | 100 | spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); |
104 | dev = __pci_get_device_by_addr(addr); | 101 | dev = __pci_addr_cache_get_device(addr); |
105 | spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); | 102 | spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); |
106 | return dev; | 103 | return dev; |
107 | } | 104 | } |
@@ -166,7 +163,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, | |||
166 | 163 | ||
167 | #ifdef DEBUG | 164 | #ifdef DEBUG |
168 | printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", | 165 | printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", |
169 | alo, ahi, pci_name (dev)); | 166 | alo, ahi, pci_name(dev)); |
170 | #endif | 167 | #endif |
171 | 168 | ||
172 | rb_link_node(&piar->rb_node, parent, p); | 169 | rb_link_node(&piar->rb_node, parent, p); |
@@ -178,7 +175,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, | |||
178 | static void __pci_addr_cache_insert_device(struct pci_dev *dev) | 175 | static void __pci_addr_cache_insert_device(struct pci_dev *dev) |
179 | { | 176 | { |
180 | struct device_node *dn; | 177 | struct device_node *dn; |
181 | struct pci_dn *pdn; | 178 | struct eeh_dev *edev; |
182 | int i; | 179 | int i; |
183 | 180 | ||
184 | dn = pci_device_to_OF_node(dev); | 181 | dn = pci_device_to_OF_node(dev); |
@@ -187,13 +184,19 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) | |||
187 | return; | 184 | return; |
188 | } | 185 | } |
189 | 186 | ||
187 | edev = of_node_to_eeh_dev(dn); | ||
188 | if (!edev) { | ||
189 | pr_warning("PCI: no EEH dev found for dn=%s\n", | ||
190 | dn->full_name); | ||
191 | return; | ||
192 | } | ||
193 | |||
190 | /* Skip any devices for which EEH is not enabled. */ | 194 | /* Skip any devices for which EEH is not enabled. */ |
191 | pdn = PCI_DN(dn); | 195 | if (!(edev->mode & EEH_MODE_SUPPORTED) || |
192 | if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || | 196 | edev->mode & EEH_MODE_NOCHECK) { |
193 | pdn->eeh_mode & EEH_MODE_NOCHECK) { | ||
194 | #ifdef DEBUG | 197 | #ifdef DEBUG |
195 | printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n", | 198 | pr_info("PCI: skip building address cache for=%s - %s\n", |
196 | pci_name(dev), pdn->node->full_name); | 199 | pci_name(dev), dn->full_name); |
197 | #endif | 200 | #endif |
198 | return; | 201 | return; |
199 | } | 202 | } |
@@ -284,6 +287,7 @@ void pci_addr_cache_remove_device(struct pci_dev *dev) | |||
284 | void __init pci_addr_cache_build(void) | 287 | void __init pci_addr_cache_build(void) |
285 | { | 288 | { |
286 | struct device_node *dn; | 289 | struct device_node *dn; |
290 | struct eeh_dev *edev; | ||
287 | struct pci_dev *dev = NULL; | 291 | struct pci_dev *dev = NULL; |
288 | 292 | ||
289 | spin_lock_init(&pci_io_addr_cache_root.piar_lock); | 293 | spin_lock_init(&pci_io_addr_cache_root.piar_lock); |
@@ -294,8 +298,14 @@ void __init pci_addr_cache_build(void) | |||
294 | dn = pci_device_to_OF_node(dev); | 298 | dn = pci_device_to_OF_node(dev); |
295 | if (!dn) | 299 | if (!dn) |
296 | continue; | 300 | continue; |
301 | |||
302 | edev = of_node_to_eeh_dev(dn); | ||
303 | if (!edev) | ||
304 | continue; | ||
305 | |||
297 | pci_dev_get(dev); /* matching put is in eeh_remove_device() */ | 306 | pci_dev_get(dev); /* matching put is in eeh_remove_device() */ |
298 | PCI_DN(dn)->pcidev = dev; | 307 | dev->dev.archdata.edev = edev; |
308 | edev->pdev = dev; | ||
299 | 309 | ||
300 | eeh_sysfs_add_device(dev); | 310 | eeh_sysfs_add_device(dev); |
301 | } | 311 | } |
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/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 1b6cb10589e0..baf92cd9dfab 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c | |||
@@ -33,8 +33,14 @@ | |||
33 | #include <asm/prom.h> | 33 | #include <asm/prom.h> |
34 | #include <asm/rtas.h> | 34 | #include <asm/rtas.h> |
35 | 35 | ||
36 | 36 | /** | |
37 | static inline const char * pcid_name (struct pci_dev *pdev) | 37 | * eeh_pcid_name - Retrieve name of PCI device driver |
38 | * @pdev: PCI device | ||
39 | * | ||
40 | * This routine is used to retrieve the name of PCI device driver | ||
41 | * if that's valid. | ||
42 | */ | ||
43 | static inline const char *eeh_pcid_name(struct pci_dev *pdev) | ||
38 | { | 44 | { |
39 | if (pdev && pdev->dev.driver) | 45 | if (pdev && pdev->dev.driver) |
40 | return pdev->dev.driver->name; | 46 | return pdev->dev.driver->name; |
@@ -64,48 +70,59 @@ static void print_device_node_tree(struct pci_dn *pdn, int dent) | |||
64 | #endif | 70 | #endif |
65 | 71 | ||
66 | /** | 72 | /** |
67 | * eeh_disable_irq - disable interrupt for the recovering device | 73 | * eeh_disable_irq - Disable interrupt for the recovering device |
74 | * @dev: PCI device | ||
75 | * | ||
76 | * This routine must be called when reporting temporary or permanent | ||
77 | * error to the particular PCI device to disable interrupt of that | ||
78 | * device. If the device has enabled MSI or MSI-X interrupt, we needn't | ||
79 | * do real work because EEH should freeze DMA transfers for those PCI | ||
80 | * devices encountering EEH errors, which includes MSI or MSI-X. | ||
68 | */ | 81 | */ |
69 | static void eeh_disable_irq(struct pci_dev *dev) | 82 | static void eeh_disable_irq(struct pci_dev *dev) |
70 | { | 83 | { |
71 | struct device_node *dn = pci_device_to_OF_node(dev); | 84 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); |
72 | 85 | ||
73 | /* Don't disable MSI and MSI-X interrupts. They are | 86 | /* Don't disable MSI and MSI-X interrupts. They are |
74 | * effectively disabled by the DMA Stopped state | 87 | * effectively disabled by the DMA Stopped state |
75 | * when an EEH error occurs. | 88 | * when an EEH error occurs. |
76 | */ | 89 | */ |
77 | if (dev->msi_enabled || dev->msix_enabled) | 90 | if (dev->msi_enabled || dev->msix_enabled) |
78 | return; | 91 | return; |
79 | 92 | ||
80 | if (!irq_has_action(dev->irq)) | 93 | if (!irq_has_action(dev->irq)) |
81 | return; | 94 | return; |
82 | 95 | ||
83 | PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; | 96 | edev->mode |= EEH_MODE_IRQ_DISABLED; |
84 | disable_irq_nosync(dev->irq); | 97 | disable_irq_nosync(dev->irq); |
85 | } | 98 | } |
86 | 99 | ||
87 | /** | 100 | /** |
88 | * eeh_enable_irq - enable interrupt for the recovering device | 101 | * eeh_enable_irq - Enable interrupt for the recovering device |
102 | * @dev: PCI device | ||
103 | * | ||
104 | * This routine must be called to enable interrupt while failed | ||
105 | * device could be resumed. | ||
89 | */ | 106 | */ |
90 | static void eeh_enable_irq(struct pci_dev *dev) | 107 | static void eeh_enable_irq(struct pci_dev *dev) |
91 | { | 108 | { |
92 | struct device_node *dn = pci_device_to_OF_node(dev); | 109 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); |
93 | 110 | ||
94 | if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { | 111 | if ((edev->mode) & EEH_MODE_IRQ_DISABLED) { |
95 | PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; | 112 | edev->mode &= ~EEH_MODE_IRQ_DISABLED; |
96 | enable_irq(dev->irq); | 113 | enable_irq(dev->irq); |
97 | } | 114 | } |
98 | } | 115 | } |
99 | 116 | ||
100 | /* ------------------------------------------------------- */ | ||
101 | /** | 117 | /** |
102 | * eeh_report_error - report pci error to each device driver | 118 | * eeh_report_error - Report pci error to each device driver |
119 | * @dev: PCI device | ||
120 | * @userdata: return value | ||
103 | * | 121 | * |
104 | * Report an EEH error to each device driver, collect up and | 122 | * Report an EEH error to each device driver, collect up and |
105 | * merge the device driver responses. Cumulative response | 123 | * merge the device driver responses. Cumulative response |
106 | * passed back in "userdata". | 124 | * passed back in "userdata". |
107 | */ | 125 | */ |
108 | |||
109 | static int eeh_report_error(struct pci_dev *dev, void *userdata) | 126 | static int eeh_report_error(struct pci_dev *dev, void *userdata) |
110 | { | 127 | { |
111 | enum pci_ers_result rc, *res = userdata; | 128 | enum pci_ers_result rc, *res = userdata; |
@@ -122,7 +139,7 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) | |||
122 | !driver->err_handler->error_detected) | 139 | !driver->err_handler->error_detected) |
123 | return 0; | 140 | return 0; |
124 | 141 | ||
125 | rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen); | 142 | rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); |
126 | 143 | ||
127 | /* A driver that needs a reset trumps all others */ | 144 | /* A driver that needs a reset trumps all others */ |
128 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; | 145 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; |
@@ -132,13 +149,14 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) | |||
132 | } | 149 | } |
133 | 150 | ||
134 | /** | 151 | /** |
135 | * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled | 152 | * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled |
153 | * @dev: PCI device | ||
154 | * @userdata: return value | ||
136 | * | 155 | * |
137 | * Tells each device driver that IO ports, MMIO and config space I/O | 156 | * Tells each device driver that IO ports, MMIO and config space I/O |
138 | * are now enabled. Collects up and merges the device driver responses. | 157 | * are now enabled. Collects up and merges the device driver responses. |
139 | * Cumulative response passed back in "userdata". | 158 | * Cumulative response passed back in "userdata". |
140 | */ | 159 | */ |
141 | |||
142 | static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) | 160 | static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) |
143 | { | 161 | { |
144 | enum pci_ers_result rc, *res = userdata; | 162 | enum pci_ers_result rc, *res = userdata; |
@@ -149,7 +167,7 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) | |||
149 | !driver->err_handler->mmio_enabled) | 167 | !driver->err_handler->mmio_enabled) |
150 | return 0; | 168 | return 0; |
151 | 169 | ||
152 | rc = driver->err_handler->mmio_enabled (dev); | 170 | rc = driver->err_handler->mmio_enabled(dev); |
153 | 171 | ||
154 | /* A driver that needs a reset trumps all others */ | 172 | /* A driver that needs a reset trumps all others */ |
155 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; | 173 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; |
@@ -159,9 +177,15 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) | |||
159 | } | 177 | } |
160 | 178 | ||
161 | /** | 179 | /** |
162 | * eeh_report_reset - tell device that slot has been reset | 180 | * eeh_report_reset - Tell device that slot has been reset |
181 | * @dev: PCI device | ||
182 | * @userdata: return value | ||
183 | * | ||
184 | * This routine must be called while EEH tries to reset particular | ||
185 | * PCI device so that the associated PCI device driver could take | ||
186 | * some actions, usually to save data the driver needs so that the | ||
187 | * driver can work again while the device is recovered. | ||
163 | */ | 188 | */ |
164 | |||
165 | static int eeh_report_reset(struct pci_dev *dev, void *userdata) | 189 | static int eeh_report_reset(struct pci_dev *dev, void *userdata) |
166 | { | 190 | { |
167 | enum pci_ers_result rc, *res = userdata; | 191 | enum pci_ers_result rc, *res = userdata; |
@@ -188,9 +212,14 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata) | |||
188 | } | 212 | } |
189 | 213 | ||
190 | /** | 214 | /** |
191 | * eeh_report_resume - tell device to resume normal operations | 215 | * eeh_report_resume - Tell device to resume normal operations |
216 | * @dev: PCI device | ||
217 | * @userdata: return value | ||
218 | * | ||
219 | * This routine must be called to notify the device driver that it | ||
220 | * could resume so that the device driver can do some initialization | ||
221 | * to make the recovered device work again. | ||
192 | */ | 222 | */ |
193 | |||
194 | static int eeh_report_resume(struct pci_dev *dev, void *userdata) | 223 | static int eeh_report_resume(struct pci_dev *dev, void *userdata) |
195 | { | 224 | { |
196 | struct pci_driver *driver = dev->driver; | 225 | struct pci_driver *driver = dev->driver; |
@@ -212,12 +241,13 @@ static int eeh_report_resume(struct pci_dev *dev, void *userdata) | |||
212 | } | 241 | } |
213 | 242 | ||
214 | /** | 243 | /** |
215 | * eeh_report_failure - tell device driver that device is dead. | 244 | * eeh_report_failure - Tell device driver that device is dead. |
245 | * @dev: PCI device | ||
246 | * @userdata: return value | ||
216 | * | 247 | * |
217 | * This informs the device driver that the device is permanently | 248 | * This informs the device driver that the device is permanently |
218 | * dead, and that no further recovery attempts will be made on it. | 249 | * dead, and that no further recovery attempts will be made on it. |
219 | */ | 250 | */ |
220 | |||
221 | static int eeh_report_failure(struct pci_dev *dev, void *userdata) | 251 | static int eeh_report_failure(struct pci_dev *dev, void *userdata) |
222 | { | 252 | { |
223 | struct pci_driver *driver = dev->driver; | 253 | struct pci_driver *driver = dev->driver; |
@@ -238,65 +268,46 @@ static int eeh_report_failure(struct pci_dev *dev, void *userdata) | |||
238 | return 0; | 268 | return 0; |
239 | } | 269 | } |
240 | 270 | ||
241 | /* ------------------------------------------------------- */ | ||
242 | /** | 271 | /** |
243 | * handle_eeh_events -- reset a PCI device after hard lockup. | 272 | * eeh_reset_device - Perform actual reset of a pci slot |
244 | * | 273 | * @edev: PE associated EEH device |
245 | * pSeries systems will isolate a PCI slot if the PCI-Host | 274 | * @bus: PCI bus corresponding to the isolcated slot |
246 | * bridge detects address or data parity errors, DMA's | ||
247 | * occurring to wild addresses (which usually happen due to | ||
248 | * bugs in device drivers or in PCI adapter firmware). | ||
249 | * Slot isolations also occur if #SERR, #PERR or other misc | ||
250 | * PCI-related errors are detected. | ||
251 | * | 275 | * |
252 | * Recovery process consists of unplugging the device driver | 276 | * This routine must be called to do reset on the indicated PE. |
253 | * (which generated hotplug events to userspace), then issuing | 277 | * During the reset, udev might be invoked because those affected |
254 | * a PCI #RST to the device, then reconfiguring the PCI config | 278 | * PCI devices will be removed and then added. |
255 | * space for all bridges & devices under this slot, and then | ||
256 | * finally restarting the device drivers (which cause a second | ||
257 | * set of hotplug events to go out to userspace). | ||
258 | */ | 279 | */ |
259 | 280 | static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) | |
260 | /** | ||
261 | * eeh_reset_device() -- perform actual reset of a pci slot | ||
262 | * @bus: pointer to the pci bus structure corresponding | ||
263 | * to the isolated slot. A non-null value will | ||
264 | * cause all devices under the bus to be removed | ||
265 | * and then re-added. | ||
266 | * @pe_dn: pointer to a "Partionable Endpoint" device node. | ||
267 | * This is the top-level structure on which pci | ||
268 | * bus resets can be performed. | ||
269 | */ | ||
270 | |||
271 | static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) | ||
272 | { | 281 | { |
273 | struct device_node *dn; | 282 | struct device_node *dn; |
274 | int cnt, rc; | 283 | int cnt, rc; |
275 | 284 | ||
276 | /* pcibios will clear the counter; save the value */ | 285 | /* pcibios will clear the counter; save the value */ |
277 | cnt = pe_dn->eeh_freeze_count; | 286 | cnt = edev->freeze_count; |
278 | 287 | ||
279 | if (bus) | 288 | if (bus) |
280 | pcibios_remove_pci_devices(bus); | 289 | pcibios_remove_pci_devices(bus); |
281 | 290 | ||
282 | /* Reset the pci controller. (Asserts RST#; resets config space). | 291 | /* Reset the pci controller. (Asserts RST#; resets config space). |
283 | * Reconfigure bridges and devices. Don't try to bring the system | 292 | * Reconfigure bridges and devices. Don't try to bring the system |
284 | * up if the reset failed for some reason. */ | 293 | * up if the reset failed for some reason. |
285 | rc = rtas_set_slot_reset(pe_dn); | 294 | */ |
295 | rc = eeh_reset_pe(edev); | ||
286 | if (rc) | 296 | if (rc) |
287 | return rc; | 297 | return rc; |
288 | 298 | ||
289 | /* Walk over all functions on this device. */ | 299 | /* Walk over all functions on this device. */ |
290 | dn = pe_dn->node; | 300 | dn = eeh_dev_to_of_node(edev); |
291 | if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) | 301 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) |
292 | dn = dn->parent->child; | 302 | dn = dn->parent->child; |
293 | 303 | ||
294 | while (dn) { | 304 | while (dn) { |
295 | struct pci_dn *ppe = PCI_DN(dn); | 305 | struct eeh_dev *pedev = of_node_to_eeh_dev(dn); |
306 | |||
296 | /* On Power4, always true because eeh_pe_config_addr=0 */ | 307 | /* On Power4, always true because eeh_pe_config_addr=0 */ |
297 | if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { | 308 | if (edev->pe_config_addr == pedev->pe_config_addr) { |
298 | rtas_configure_bridge(ppe); | 309 | eeh_ops->configure_bridge(dn); |
299 | eeh_restore_bars(ppe); | 310 | eeh_restore_bars(pedev); |
300 | } | 311 | } |
301 | dn = dn->sibling; | 312 | dn = dn->sibling; |
302 | } | 313 | } |
@@ -308,10 +319,10 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) | |||
308 | * potentially weird things happen. | 319 | * potentially weird things happen. |
309 | */ | 320 | */ |
310 | if (bus) { | 321 | if (bus) { |
311 | ssleep (5); | 322 | ssleep(5); |
312 | pcibios_add_pci_devices(bus); | 323 | pcibios_add_pci_devices(bus); |
313 | } | 324 | } |
314 | pe_dn->eeh_freeze_count = cnt; | 325 | edev->freeze_count = cnt; |
315 | 326 | ||
316 | return 0; | 327 | return 0; |
317 | } | 328 | } |
@@ -321,23 +332,39 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) | |||
321 | */ | 332 | */ |
322 | #define MAX_WAIT_FOR_RECOVERY 150 | 333 | #define MAX_WAIT_FOR_RECOVERY 150 |
323 | 334 | ||
324 | struct pci_dn * handle_eeh_events (struct eeh_event *event) | 335 | /** |
336 | * eeh_handle_event - Reset a PCI device after hard lockup. | ||
337 | * @event: EEH event | ||
338 | * | ||
339 | * While PHB detects address or data parity errors on particular PCI | ||
340 | * slot, the associated PE will be frozen. Besides, DMA's occurring | ||
341 | * to wild addresses (which usually happen due to bugs in device | ||
342 | * drivers or in PCI adapter firmware) can cause EEH error. #SERR, | ||
343 | * #PERR or other misc PCI-related errors also can trigger EEH errors. | ||
344 | * | ||
345 | * Recovery process consists of unplugging the device driver (which | ||
346 | * generated hotplug events to userspace), then issuing a PCI #RST to | ||
347 | * the device, then reconfiguring the PCI config space for all bridges | ||
348 | * & devices under this slot, and then finally restarting the device | ||
349 | * drivers (which cause a second set of hotplug events to go out to | ||
350 | * userspace). | ||
351 | */ | ||
352 | struct eeh_dev *handle_eeh_events(struct eeh_event *event) | ||
325 | { | 353 | { |
326 | struct device_node *frozen_dn; | 354 | struct device_node *frozen_dn; |
327 | struct pci_dn *frozen_pdn; | 355 | struct eeh_dev *frozen_edev; |
328 | struct pci_bus *frozen_bus; | 356 | struct pci_bus *frozen_bus; |
329 | int rc = 0; | 357 | int rc = 0; |
330 | enum pci_ers_result result = PCI_ERS_RESULT_NONE; | 358 | enum pci_ers_result result = PCI_ERS_RESULT_NONE; |
331 | const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; | 359 | const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; |
332 | 360 | ||
333 | frozen_dn = find_device_pe(event->dn); | 361 | frozen_dn = eeh_find_device_pe(eeh_dev_to_of_node(event->edev)); |
334 | if (!frozen_dn) { | 362 | if (!frozen_dn) { |
335 | 363 | location = of_get_property(eeh_dev_to_of_node(event->edev), "ibm,loc-code", NULL); | |
336 | location = of_get_property(event->dn, "ibm,loc-code", NULL); | ||
337 | location = location ? location : "unknown"; | 364 | location = location ? location : "unknown"; |
338 | printk(KERN_ERR "EEH: Error: Cannot find partition endpoint " | 365 | printk(KERN_ERR "EEH: Error: Cannot find partition endpoint " |
339 | "for location=%s pci addr=%s\n", | 366 | "for location=%s pci addr=%s\n", |
340 | location, eeh_pci_name(event->dev)); | 367 | location, eeh_pci_name(eeh_dev_to_pci_dev(event->edev))); |
341 | return NULL; | 368 | return NULL; |
342 | } | 369 | } |
343 | 370 | ||
@@ -350,9 +377,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
350 | * which was always an EADS pci bridge. In the new style, | 377 | * which was always an EADS pci bridge. In the new style, |
351 | * there might not be any EADS bridges, and even when there are, | 378 | * there might not be any EADS bridges, and even when there are, |
352 | * the firmware marks them as "EEH incapable". So another | 379 | * the firmware marks them as "EEH incapable". So another |
353 | * two-step is needed to find the pci bus.. */ | 380 | * two-step is needed to find the pci bus.. |
381 | */ | ||
354 | if (!frozen_bus) | 382 | if (!frozen_bus) |
355 | frozen_bus = pcibios_find_pci_bus (frozen_dn->parent); | 383 | frozen_bus = pcibios_find_pci_bus(frozen_dn->parent); |
356 | 384 | ||
357 | if (!frozen_bus) { | 385 | if (!frozen_bus) { |
358 | printk(KERN_ERR "EEH: Cannot find PCI bus " | 386 | printk(KERN_ERR "EEH: Cannot find PCI bus " |
@@ -361,22 +389,21 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
361 | return NULL; | 389 | return NULL; |
362 | } | 390 | } |
363 | 391 | ||
364 | frozen_pdn = PCI_DN(frozen_dn); | 392 | frozen_edev = of_node_to_eeh_dev(frozen_dn); |
365 | frozen_pdn->eeh_freeze_count++; | 393 | frozen_edev->freeze_count++; |
394 | pci_str = eeh_pci_name(eeh_dev_to_pci_dev(event->edev)); | ||
395 | drv_str = eeh_pcid_name(eeh_dev_to_pci_dev(event->edev)); | ||
366 | 396 | ||
367 | pci_str = eeh_pci_name(event->dev); | 397 | if (frozen_edev->freeze_count > EEH_MAX_ALLOWED_FREEZES) |
368 | drv_str = pcid_name(event->dev); | ||
369 | |||
370 | if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) | ||
371 | goto excess_failures; | 398 | goto excess_failures; |
372 | 399 | ||
373 | printk(KERN_WARNING | 400 | printk(KERN_WARNING |
374 | "EEH: This PCI device has failed %d times in the last hour:\n", | 401 | "EEH: This PCI device has failed %d times in the last hour:\n", |
375 | frozen_pdn->eeh_freeze_count); | 402 | frozen_edev->freeze_count); |
376 | 403 | ||
377 | if (frozen_pdn->pcidev) { | 404 | if (frozen_edev->pdev) { |
378 | bus_pci_str = pci_name(frozen_pdn->pcidev); | 405 | bus_pci_str = pci_name(frozen_edev->pdev); |
379 | bus_drv_str = pcid_name(frozen_pdn->pcidev); | 406 | bus_drv_str = eeh_pcid_name(frozen_edev->pdev); |
380 | printk(KERN_WARNING | 407 | printk(KERN_WARNING |
381 | "EEH: Bus location=%s driver=%s pci addr=%s\n", | 408 | "EEH: Bus location=%s driver=%s pci addr=%s\n", |
382 | location, bus_drv_str, bus_pci_str); | 409 | location, bus_drv_str, bus_pci_str); |
@@ -395,9 +422,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
395 | pci_walk_bus(frozen_bus, eeh_report_error, &result); | 422 | pci_walk_bus(frozen_bus, eeh_report_error, &result); |
396 | 423 | ||
397 | /* Get the current PCI slot state. This can take a long time, | 424 | /* Get the current PCI slot state. This can take a long time, |
398 | * sometimes over 3 seconds for certain systems. */ | 425 | * sometimes over 3 seconds for certain systems. |
399 | rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000); | 426 | */ |
400 | if (rc < 0) { | 427 | rc = eeh_ops->wait_state(eeh_dev_to_of_node(frozen_edev), MAX_WAIT_FOR_RECOVERY*1000); |
428 | if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { | ||
401 | printk(KERN_WARNING "EEH: Permanent failure\n"); | 429 | printk(KERN_WARNING "EEH: Permanent failure\n"); |
402 | goto hard_fail; | 430 | goto hard_fail; |
403 | } | 431 | } |
@@ -406,14 +434,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
406 | * don't post the error log until after all dev drivers | 434 | * don't post the error log until after all dev drivers |
407 | * have been informed. | 435 | * have been informed. |
408 | */ | 436 | */ |
409 | eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE); | 437 | eeh_slot_error_detail(frozen_edev, EEH_LOG_TEMP); |
410 | 438 | ||
411 | /* If all device drivers were EEH-unaware, then shut | 439 | /* If all device drivers were EEH-unaware, then shut |
412 | * down all of the device drivers, and hope they | 440 | * down all of the device drivers, and hope they |
413 | * go down willingly, without panicing the system. | 441 | * go down willingly, without panicing the system. |
414 | */ | 442 | */ |
415 | if (result == PCI_ERS_RESULT_NONE) { | 443 | if (result == PCI_ERS_RESULT_NONE) { |
416 | rc = eeh_reset_device(frozen_pdn, frozen_bus); | 444 | rc = eeh_reset_device(frozen_edev, frozen_bus); |
417 | if (rc) { | 445 | if (rc) { |
418 | printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); | 446 | printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); |
419 | goto hard_fail; | 447 | goto hard_fail; |
@@ -422,7 +450,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
422 | 450 | ||
423 | /* If all devices reported they can proceed, then re-enable MMIO */ | 451 | /* If all devices reported they can proceed, then re-enable MMIO */ |
424 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { | 452 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { |
425 | rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO); | 453 | rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_MMIO); |
426 | 454 | ||
427 | if (rc < 0) | 455 | if (rc < 0) |
428 | goto hard_fail; | 456 | goto hard_fail; |
@@ -436,7 +464,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
436 | 464 | ||
437 | /* If all devices reported they can proceed, then re-enable DMA */ | 465 | /* If all devices reported they can proceed, then re-enable DMA */ |
438 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { | 466 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { |
439 | rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA); | 467 | rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_DMA); |
440 | 468 | ||
441 | if (rc < 0) | 469 | if (rc < 0) |
442 | goto hard_fail; | 470 | goto hard_fail; |
@@ -454,7 +482,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
454 | 482 | ||
455 | /* If any device called out for a reset, then reset the slot */ | 483 | /* If any device called out for a reset, then reset the slot */ |
456 | if (result == PCI_ERS_RESULT_NEED_RESET) { | 484 | if (result == PCI_ERS_RESULT_NEED_RESET) { |
457 | rc = eeh_reset_device(frozen_pdn, NULL); | 485 | rc = eeh_reset_device(frozen_edev, NULL); |
458 | if (rc) { | 486 | if (rc) { |
459 | printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); | 487 | printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); |
460 | goto hard_fail; | 488 | goto hard_fail; |
@@ -473,7 +501,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
473 | /* Tell all device drivers that they can resume operations */ | 501 | /* Tell all device drivers that they can resume operations */ |
474 | pci_walk_bus(frozen_bus, eeh_report_resume, NULL); | 502 | pci_walk_bus(frozen_bus, eeh_report_resume, NULL); |
475 | 503 | ||
476 | return frozen_pdn; | 504 | return frozen_edev; |
477 | 505 | ||
478 | excess_failures: | 506 | excess_failures: |
479 | /* | 507 | /* |
@@ -486,7 +514,7 @@ excess_failures: | |||
486 | "has failed %d times in the last hour " | 514 | "has failed %d times in the last hour " |
487 | "and has been permanently disabled.\n" | 515 | "and has been permanently disabled.\n" |
488 | "Please try reseating this device or replacing it.\n", | 516 | "Please try reseating this device or replacing it.\n", |
489 | location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); | 517 | location, drv_str, pci_str, frozen_edev->freeze_count); |
490 | goto perm_error; | 518 | goto perm_error; |
491 | 519 | ||
492 | hard_fail: | 520 | hard_fail: |
@@ -497,7 +525,7 @@ hard_fail: | |||
497 | location, drv_str, pci_str); | 525 | location, drv_str, pci_str); |
498 | 526 | ||
499 | perm_error: | 527 | perm_error: |
500 | eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE); | 528 | eeh_slot_error_detail(frozen_edev, EEH_LOG_PERM); |
501 | 529 | ||
502 | /* Notify all devices that they're about to go down. */ | 530 | /* Notify all devices that they're about to go down. */ |
503 | pci_walk_bus(frozen_bus, eeh_report_failure, NULL); | 531 | pci_walk_bus(frozen_bus, eeh_report_failure, NULL); |
@@ -508,4 +536,3 @@ perm_error: | |||
508 | return NULL; | 536 | return NULL; |
509 | } | 537 | } |
510 | 538 | ||
511 | /* ---------- end of file ---------- */ | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index d2383cfb6dfd..4a4752565856 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * eeh_event.c | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | 2 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 3 | * it under the terms of the GNU General Public License as published by |
6 | * the Free Software Foundation; either version 2 of the License, or | 4 | * the Free Software Foundation; either version 2 of the License, or |
@@ -46,7 +44,7 @@ DECLARE_WORK(eeh_event_wq, eeh_thread_launcher); | |||
46 | DEFINE_MUTEX(eeh_event_mutex); | 44 | DEFINE_MUTEX(eeh_event_mutex); |
47 | 45 | ||
48 | /** | 46 | /** |
49 | * eeh_event_handler - dispatch EEH events. | 47 | * eeh_event_handler - Dispatch EEH events. |
50 | * @dummy - unused | 48 | * @dummy - unused |
51 | * | 49 | * |
52 | * The detection of a frozen slot can occur inside an interrupt, | 50 | * The detection of a frozen slot can occur inside an interrupt, |
@@ -58,10 +56,10 @@ DEFINE_MUTEX(eeh_event_mutex); | |||
58 | static int eeh_event_handler(void * dummy) | 56 | static int eeh_event_handler(void * dummy) |
59 | { | 57 | { |
60 | unsigned long flags; | 58 | unsigned long flags; |
61 | struct eeh_event *event; | 59 | struct eeh_event *event; |
62 | struct pci_dn *pdn; | 60 | struct eeh_dev *edev; |
63 | 61 | ||
64 | daemonize ("eehd"); | 62 | daemonize("eehd"); |
65 | set_current_state(TASK_INTERRUPTIBLE); | 63 | set_current_state(TASK_INTERRUPTIBLE); |
66 | 64 | ||
67 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | 65 | spin_lock_irqsave(&eeh_eventlist_lock, flags); |
@@ -79,31 +77,37 @@ static int eeh_event_handler(void * dummy) | |||
79 | 77 | ||
80 | /* Serialize processing of EEH events */ | 78 | /* Serialize processing of EEH events */ |
81 | mutex_lock(&eeh_event_mutex); | 79 | mutex_lock(&eeh_event_mutex); |
82 | eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); | 80 | edev = event->edev; |
81 | eeh_mark_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); | ||
83 | 82 | ||
84 | printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", | 83 | printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", |
85 | eeh_pci_name(event->dev)); | 84 | eeh_pci_name(edev->pdev)); |
85 | |||
86 | edev = handle_eeh_events(event); | ||
86 | 87 | ||
87 | pdn = handle_eeh_events(event); | 88 | eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); |
89 | pci_dev_put(edev->pdev); | ||
88 | 90 | ||
89 | eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); | ||
90 | pci_dev_put(event->dev); | ||
91 | kfree(event); | 91 | kfree(event); |
92 | mutex_unlock(&eeh_event_mutex); | 92 | mutex_unlock(&eeh_event_mutex); |
93 | 93 | ||
94 | /* If there are no new errors after an hour, clear the counter. */ | 94 | /* If there are no new errors after an hour, clear the counter. */ |
95 | if (pdn && pdn->eeh_freeze_count>0) { | 95 | if (edev && edev->freeze_count>0) { |
96 | msleep_interruptible (3600*1000); | 96 | msleep_interruptible(3600*1000); |
97 | if (pdn->eeh_freeze_count>0) | 97 | if (edev->freeze_count>0) |
98 | pdn->eeh_freeze_count--; | 98 | edev->freeze_count--; |
99 | |||
99 | } | 100 | } |
100 | 101 | ||
101 | return 0; | 102 | return 0; |
102 | } | 103 | } |
103 | 104 | ||
104 | /** | 105 | /** |
105 | * eeh_thread_launcher | 106 | * eeh_thread_launcher - Start kernel thread to handle EEH events |
106 | * @dummy - unused | 107 | * @dummy - unused |
108 | * | ||
109 | * This routine is called to start the kernel thread for processing | ||
110 | * EEH event. | ||
107 | */ | 111 | */ |
108 | static void eeh_thread_launcher(struct work_struct *dummy) | 112 | static void eeh_thread_launcher(struct work_struct *dummy) |
109 | { | 113 | { |
@@ -112,18 +116,18 @@ static void eeh_thread_launcher(struct work_struct *dummy) | |||
112 | } | 116 | } |
113 | 117 | ||
114 | /** | 118 | /** |
115 | * eeh_send_failure_event - generate a PCI error event | 119 | * eeh_send_failure_event - Generate a PCI error event |
116 | * @dev pci device | 120 | * @edev: EEH device |
117 | * | 121 | * |
118 | * This routine can be called within an interrupt context; | 122 | * This routine can be called within an interrupt context; |
119 | * the actual event will be delivered in a normal context | 123 | * the actual event will be delivered in a normal context |
120 | * (from a workqueue). | 124 | * (from a workqueue). |
121 | */ | 125 | */ |
122 | int eeh_send_failure_event (struct device_node *dn, | 126 | int eeh_send_failure_event(struct eeh_dev *edev) |
123 | struct pci_dev *dev) | ||
124 | { | 127 | { |
125 | unsigned long flags; | 128 | unsigned long flags; |
126 | struct eeh_event *event; | 129 | struct eeh_event *event; |
130 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
127 | const char *location; | 131 | const char *location; |
128 | 132 | ||
129 | if (!mem_init_done) { | 133 | if (!mem_init_done) { |
@@ -135,15 +139,14 @@ int eeh_send_failure_event (struct device_node *dn, | |||
135 | } | 139 | } |
136 | event = kmalloc(sizeof(*event), GFP_ATOMIC); | 140 | event = kmalloc(sizeof(*event), GFP_ATOMIC); |
137 | if (event == NULL) { | 141 | if (event == NULL) { |
138 | printk (KERN_ERR "EEH: out of memory, event not handled\n"); | 142 | printk(KERN_ERR "EEH: out of memory, event not handled\n"); |
139 | return 1; | 143 | return 1; |
140 | } | 144 | } |
141 | 145 | ||
142 | if (dev) | 146 | if (edev->pdev) |
143 | pci_dev_get(dev); | 147 | pci_dev_get(edev->pdev); |
144 | 148 | ||
145 | event->dn = dn; | 149 | event->edev = edev; |
146 | event->dev = dev; | ||
147 | 150 | ||
148 | /* We may or may not be called in an interrupt context */ | 151 | /* We may or may not be called in an interrupt context */ |
149 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | 152 | spin_lock_irqsave(&eeh_eventlist_lock, flags); |
@@ -154,5 +157,3 @@ int eeh_send_failure_event (struct device_node *dn, | |||
154 | 157 | ||
155 | return 0; | 158 | return 0; |
156 | } | 159 | } |
157 | |||
158 | /********************** END OF FILE ******************************/ | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c new file mode 100644 index 000000000000..8752f79a6af8 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c | |||
@@ -0,0 +1,565 @@ | |||
1 | /* | ||
2 | * The file intends to implement the platform dependent EEH operations on pseries. | ||
3 | * Actually, the pseries platform is built based on RTAS heavily. That means the | ||
4 | * pseries platform dependent EEH operations will be built on RTAS calls. The functions | ||
5 | * are devired from arch/powerpc/platforms/pseries/eeh.c and necessary cleanup has | ||
6 | * been done. | ||
7 | * | ||
8 | * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2011. | ||
9 | * Copyright IBM Corporation 2001, 2005, 2006 | ||
10 | * Copyright Dave Engebretsen & Todd Inglett 2001 | ||
11 | * Copyright Linas Vepstas 2005, 2006 | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | */ | ||
27 | |||
28 | #include <linux/atomic.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/export.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/list.h> | ||
33 | #include <linux/of.h> | ||
34 | #include <linux/pci.h> | ||
35 | #include <linux/proc_fs.h> | ||
36 | #include <linux/rbtree.h> | ||
37 | #include <linux/sched.h> | ||
38 | #include <linux/seq_file.h> | ||
39 | #include <linux/spinlock.h> | ||
40 | |||
41 | #include <asm/eeh.h> | ||
42 | #include <asm/eeh_event.h> | ||
43 | #include <asm/io.h> | ||
44 | #include <asm/machdep.h> | ||
45 | #include <asm/ppc-pci.h> | ||
46 | #include <asm/rtas.h> | ||
47 | |||
48 | /* RTAS tokens */ | ||
49 | static int ibm_set_eeh_option; | ||
50 | static int ibm_set_slot_reset; | ||
51 | static int ibm_read_slot_reset_state; | ||
52 | static int ibm_read_slot_reset_state2; | ||
53 | static int ibm_slot_error_detail; | ||
54 | static int ibm_get_config_addr_info; | ||
55 | static int ibm_get_config_addr_info2; | ||
56 | static int ibm_configure_bridge; | ||
57 | static int ibm_configure_pe; | ||
58 | |||
59 | /* | ||
60 | * Buffer for reporting slot-error-detail rtas calls. Its here | ||
61 | * in BSS, and not dynamically alloced, so that it ends up in | ||
62 | * RMO where RTAS can access it. | ||
63 | */ | ||
64 | static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; | ||
65 | static DEFINE_SPINLOCK(slot_errbuf_lock); | ||
66 | static int eeh_error_buf_size; | ||
67 | |||
68 | /** | ||
69 | * pseries_eeh_init - EEH platform dependent initialization | ||
70 | * | ||
71 | * EEH platform dependent initialization on pseries. | ||
72 | */ | ||
73 | static int pseries_eeh_init(void) | ||
74 | { | ||
75 | /* figure out EEH RTAS function call tokens */ | ||
76 | ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); | ||
77 | ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); | ||
78 | ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); | ||
79 | ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); | ||
80 | ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); | ||
81 | ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); | ||
82 | ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); | ||
83 | ibm_configure_pe = rtas_token("ibm,configure-pe"); | ||
84 | ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); | ||
85 | |||
86 | /* necessary sanity check */ | ||
87 | if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) { | ||
88 | pr_warning("%s: RTAS service <ibm,set-eeh-option> invalid\n", | ||
89 | __func__); | ||
90 | return -EINVAL; | ||
91 | } else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) { | ||
92 | pr_warning("%s: RTAS service <ibm, set-slot-reset> invalid\n", | ||
93 | __func__); | ||
94 | return -EINVAL; | ||
95 | } else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE && | ||
96 | ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) { | ||
97 | pr_warning("%s: RTAS service <ibm,read-slot-reset-state2> and " | ||
98 | "<ibm,read-slot-reset-state> invalid\n", | ||
99 | __func__); | ||
100 | return -EINVAL; | ||
101 | } else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) { | ||
102 | pr_warning("%s: RTAS service <ibm,slot-error-detail> invalid\n", | ||
103 | __func__); | ||
104 | return -EINVAL; | ||
105 | } else if (ibm_get_config_addr_info2 == RTAS_UNKNOWN_SERVICE && | ||
106 | ibm_get_config_addr_info == RTAS_UNKNOWN_SERVICE) { | ||
107 | pr_warning("%s: RTAS service <ibm,get-config-addr-info2> and " | ||
108 | "<ibm,get-config-addr-info> invalid\n", | ||
109 | __func__); | ||
110 | return -EINVAL; | ||
111 | } else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE && | ||
112 | ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) { | ||
113 | pr_warning("%s: RTAS service <ibm,configure-pe> and " | ||
114 | "<ibm,configure-bridge> invalid\n", | ||
115 | __func__); | ||
116 | return -EINVAL; | ||
117 | } | ||
118 | |||
119 | /* Initialize error log lock and size */ | ||
120 | spin_lock_init(&slot_errbuf_lock); | ||
121 | eeh_error_buf_size = rtas_token("rtas-error-log-max"); | ||
122 | if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { | ||
123 | pr_warning("%s: unknown EEH error log size\n", | ||
124 | __func__); | ||
125 | eeh_error_buf_size = 1024; | ||
126 | } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { | ||
127 | pr_warning("%s: EEH error log size %d exceeds the maximal %d\n", | ||
128 | __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX); | ||
129 | eeh_error_buf_size = RTAS_ERROR_LOG_MAX; | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable | ||
137 | * @dn: device node | ||
138 | * @option: operation to be issued | ||
139 | * | ||
140 | * The function is used to control the EEH functionality globally. | ||
141 | * Currently, following options are support according to PAPR: | ||
142 | * Enable EEH, Disable EEH, Enable MMIO and Enable DMA | ||
143 | */ | ||
144 | static int pseries_eeh_set_option(struct device_node *dn, int option) | ||
145 | { | ||
146 | int ret = 0; | ||
147 | struct eeh_dev *edev; | ||
148 | const u32 *reg; | ||
149 | int config_addr; | ||
150 | |||
151 | edev = of_node_to_eeh_dev(dn); | ||
152 | |||
153 | /* | ||
154 | * When we're enabling or disabling EEH functioality on | ||
155 | * the particular PE, the PE config address is possibly | ||
156 | * unavailable. Therefore, we have to figure it out from | ||
157 | * the FDT node. | ||
158 | */ | ||
159 | switch (option) { | ||
160 | case EEH_OPT_DISABLE: | ||
161 | case EEH_OPT_ENABLE: | ||
162 | reg = of_get_property(dn, "reg", NULL); | ||
163 | config_addr = reg[0]; | ||
164 | break; | ||
165 | |||
166 | case EEH_OPT_THAW_MMIO: | ||
167 | case EEH_OPT_THAW_DMA: | ||
168 | config_addr = edev->config_addr; | ||
169 | if (edev->pe_config_addr) | ||
170 | config_addr = edev->pe_config_addr; | ||
171 | break; | ||
172 | |||
173 | default: | ||
174 | pr_err("%s: Invalid option %d\n", | ||
175 | __func__, option); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, | ||
180 | config_addr, BUID_HI(edev->phb->buid), | ||
181 | BUID_LO(edev->phb->buid), option); | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * pseries_eeh_get_pe_addr - Retrieve PE address | ||
188 | * @dn: device node | ||
189 | * | ||
190 | * Retrieve the assocated PE address. Actually, there're 2 RTAS | ||
191 | * function calls dedicated for the purpose. We need implement | ||
192 | * it through the new function and then the old one. Besides, | ||
193 | * you should make sure the config address is figured out from | ||
194 | * FDT node before calling the function. | ||
195 | * | ||
196 | * It's notable that zero'ed return value means invalid PE config | ||
197 | * address. | ||
198 | */ | ||
199 | static int pseries_eeh_get_pe_addr(struct device_node *dn) | ||
200 | { | ||
201 | struct eeh_dev *edev; | ||
202 | int ret = 0; | ||
203 | int rets[3]; | ||
204 | |||
205 | edev = of_node_to_eeh_dev(dn); | ||
206 | |||
207 | if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { | ||
208 | /* | ||
209 | * First of all, we need to make sure there has one PE | ||
210 | * associated with the device. Otherwise, PE address is | ||
211 | * meaningless. | ||
212 | */ | ||
213 | ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, | ||
214 | edev->config_addr, BUID_HI(edev->phb->buid), | ||
215 | BUID_LO(edev->phb->buid), 1); | ||
216 | if (ret || (rets[0] == 0)) | ||
217 | return 0; | ||
218 | |||
219 | /* Retrieve the associated PE config address */ | ||
220 | ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, | ||
221 | edev->config_addr, BUID_HI(edev->phb->buid), | ||
222 | BUID_LO(edev->phb->buid), 0); | ||
223 | if (ret) { | ||
224 | pr_warning("%s: Failed to get PE address for %s\n", | ||
225 | __func__, dn->full_name); | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | return rets[0]; | ||
230 | } | ||
231 | |||
232 | if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { | ||
233 | ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets, | ||
234 | edev->config_addr, BUID_HI(edev->phb->buid), | ||
235 | BUID_LO(edev->phb->buid), 0); | ||
236 | if (ret) { | ||
237 | pr_warning("%s: Failed to get PE address for %s\n", | ||
238 | __func__, dn->full_name); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | return rets[0]; | ||
243 | } | ||
244 | |||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * pseries_eeh_get_state - Retrieve PE state | ||
250 | * @dn: PE associated device node | ||
251 | * @state: return value | ||
252 | * | ||
253 | * Retrieve the state of the specified PE. On RTAS compliant | ||
254 | * pseries platform, there already has one dedicated RTAS function | ||
255 | * for the purpose. It's notable that the associated PE config address | ||
256 | * might be ready when calling the function. Therefore, endeavour to | ||
257 | * use the PE config address if possible. Further more, there're 2 | ||
258 | * RTAS calls for the purpose, we need to try the new one and back | ||
259 | * to the old one if the new one couldn't work properly. | ||
260 | */ | ||
261 | static int pseries_eeh_get_state(struct device_node *dn, int *state) | ||
262 | { | ||
263 | struct eeh_dev *edev; | ||
264 | int config_addr; | ||
265 | int ret; | ||
266 | int rets[4]; | ||
267 | int result; | ||
268 | |||
269 | /* Figure out PE config address if possible */ | ||
270 | edev = of_node_to_eeh_dev(dn); | ||
271 | config_addr = edev->config_addr; | ||
272 | if (edev->pe_config_addr) | ||
273 | config_addr = edev->pe_config_addr; | ||
274 | |||
275 | if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { | ||
276 | ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets, | ||
277 | config_addr, BUID_HI(edev->phb->buid), | ||
278 | BUID_LO(edev->phb->buid)); | ||
279 | } else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) { | ||
280 | /* Fake PE unavailable info */ | ||
281 | rets[2] = 0; | ||
282 | ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, | ||
283 | config_addr, BUID_HI(edev->phb->buid), | ||
284 | BUID_LO(edev->phb->buid)); | ||
285 | } else { | ||
286 | return EEH_STATE_NOT_SUPPORT; | ||
287 | } | ||
288 | |||
289 | if (ret) | ||
290 | return ret; | ||
291 | |||
292 | /* Parse the result out */ | ||
293 | result = 0; | ||
294 | if (rets[1]) { | ||
295 | switch(rets[0]) { | ||
296 | case 0: | ||
297 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
298 | result |= EEH_STATE_MMIO_ACTIVE; | ||
299 | result |= EEH_STATE_DMA_ACTIVE; | ||
300 | break; | ||
301 | case 1: | ||
302 | result |= EEH_STATE_RESET_ACTIVE; | ||
303 | result |= EEH_STATE_MMIO_ACTIVE; | ||
304 | result |= EEH_STATE_DMA_ACTIVE; | ||
305 | break; | ||
306 | case 2: | ||
307 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
308 | result &= ~EEH_STATE_MMIO_ACTIVE; | ||
309 | result &= ~EEH_STATE_DMA_ACTIVE; | ||
310 | break; | ||
311 | case 4: | ||
312 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
313 | result &= ~EEH_STATE_MMIO_ACTIVE; | ||
314 | result &= ~EEH_STATE_DMA_ACTIVE; | ||
315 | result |= EEH_STATE_MMIO_ENABLED; | ||
316 | break; | ||
317 | case 5: | ||
318 | if (rets[2]) { | ||
319 | if (state) *state = rets[2]; | ||
320 | result = EEH_STATE_UNAVAILABLE; | ||
321 | } else { | ||
322 | result = EEH_STATE_NOT_SUPPORT; | ||
323 | } | ||
324 | default: | ||
325 | result = EEH_STATE_NOT_SUPPORT; | ||
326 | } | ||
327 | } else { | ||
328 | result = EEH_STATE_NOT_SUPPORT; | ||
329 | } | ||
330 | |||
331 | return result; | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * pseries_eeh_reset - Reset the specified PE | ||
336 | * @dn: PE associated device node | ||
337 | * @option: reset option | ||
338 | * | ||
339 | * Reset the specified PE | ||
340 | */ | ||
341 | static int pseries_eeh_reset(struct device_node *dn, int option) | ||
342 | { | ||
343 | struct eeh_dev *edev; | ||
344 | int config_addr; | ||
345 | int ret; | ||
346 | |||
347 | /* Figure out PE address */ | ||
348 | edev = of_node_to_eeh_dev(dn); | ||
349 | config_addr = edev->config_addr; | ||
350 | if (edev->pe_config_addr) | ||
351 | config_addr = edev->pe_config_addr; | ||
352 | |||
353 | /* Reset PE through RTAS call */ | ||
354 | ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, | ||
355 | config_addr, BUID_HI(edev->phb->buid), | ||
356 | BUID_LO(edev->phb->buid), option); | ||
357 | |||
358 | /* If fundamental-reset not supported, try hot-reset */ | ||
359 | if (option == EEH_RESET_FUNDAMENTAL && | ||
360 | ret == -8) { | ||
361 | ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, | ||
362 | config_addr, BUID_HI(edev->phb->buid), | ||
363 | BUID_LO(edev->phb->buid), EEH_RESET_HOT); | ||
364 | } | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | /** | ||
370 | * pseries_eeh_wait_state - Wait for PE state | ||
371 | * @dn: PE associated device node | ||
372 | * @max_wait: maximal period in microsecond | ||
373 | * | ||
374 | * Wait for the state of associated PE. It might take some time | ||
375 | * to retrieve the PE's state. | ||
376 | */ | ||
377 | static int pseries_eeh_wait_state(struct device_node *dn, int max_wait) | ||
378 | { | ||
379 | int ret; | ||
380 | int mwait; | ||
381 | |||
382 | /* | ||
383 | * According to PAPR, the state of PE might be temporarily | ||
384 | * unavailable. Under the circumstance, we have to wait | ||
385 | * for indicated time determined by firmware. The maximal | ||
386 | * wait time is 5 minutes, which is acquired from the original | ||
387 | * EEH implementation. Also, the original implementation | ||
388 | * also defined the minimal wait time as 1 second. | ||
389 | */ | ||
390 | #define EEH_STATE_MIN_WAIT_TIME (1000) | ||
391 | #define EEH_STATE_MAX_WAIT_TIME (300 * 1000) | ||
392 | |||
393 | while (1) { | ||
394 | ret = pseries_eeh_get_state(dn, &mwait); | ||
395 | |||
396 | /* | ||
397 | * If the PE's state is temporarily unavailable, | ||
398 | * we have to wait for the specified time. Otherwise, | ||
399 | * the PE's state will be returned immediately. | ||
400 | */ | ||
401 | if (ret != EEH_STATE_UNAVAILABLE) | ||
402 | return ret; | ||
403 | |||
404 | if (max_wait <= 0) { | ||
405 | pr_warning("%s: Timeout when getting PE's state (%d)\n", | ||
406 | __func__, max_wait); | ||
407 | return EEH_STATE_NOT_SUPPORT; | ||
408 | } | ||
409 | |||
410 | if (mwait <= 0) { | ||
411 | pr_warning("%s: Firmware returned bad wait value %d\n", | ||
412 | __func__, mwait); | ||
413 | mwait = EEH_STATE_MIN_WAIT_TIME; | ||
414 | } else if (mwait > EEH_STATE_MAX_WAIT_TIME) { | ||
415 | pr_warning("%s: Firmware returned too long wait value %d\n", | ||
416 | __func__, mwait); | ||
417 | mwait = EEH_STATE_MAX_WAIT_TIME; | ||
418 | } | ||
419 | |||
420 | max_wait -= mwait; | ||
421 | msleep(mwait); | ||
422 | } | ||
423 | |||
424 | return EEH_STATE_NOT_SUPPORT; | ||
425 | } | ||
426 | |||
427 | /** | ||
428 | * pseries_eeh_get_log - Retrieve error log | ||
429 | * @dn: device node | ||
430 | * @severity: temporary or permanent error log | ||
431 | * @drv_log: driver log to be combined with retrieved error log | ||
432 | * @len: length of driver log | ||
433 | * | ||
434 | * Retrieve the temporary or permanent error from the PE. | ||
435 | * Actually, the error will be retrieved through the dedicated | ||
436 | * RTAS call. | ||
437 | */ | ||
438 | static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len) | ||
439 | { | ||
440 | struct eeh_dev *edev; | ||
441 | int config_addr; | ||
442 | unsigned long flags; | ||
443 | int ret; | ||
444 | |||
445 | edev = of_node_to_eeh_dev(dn); | ||
446 | spin_lock_irqsave(&slot_errbuf_lock, flags); | ||
447 | memset(slot_errbuf, 0, eeh_error_buf_size); | ||
448 | |||
449 | /* Figure out the PE address */ | ||
450 | config_addr = edev->config_addr; | ||
451 | if (edev->pe_config_addr) | ||
452 | config_addr = edev->pe_config_addr; | ||
453 | |||
454 | ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr, | ||
455 | BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), | ||
456 | virt_to_phys(drv_log), len, | ||
457 | virt_to_phys(slot_errbuf), eeh_error_buf_size, | ||
458 | severity); | ||
459 | if (!ret) | ||
460 | log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); | ||
461 | spin_unlock_irqrestore(&slot_errbuf_lock, flags); | ||
462 | |||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE | ||
468 | * @dn: PE associated device node | ||
469 | * | ||
470 | * The function will be called to reconfigure the bridges included | ||
471 | * in the specified PE so that the mulfunctional PE would be recovered | ||
472 | * again. | ||
473 | */ | ||
474 | static int pseries_eeh_configure_bridge(struct device_node *dn) | ||
475 | { | ||
476 | struct eeh_dev *edev; | ||
477 | int config_addr; | ||
478 | int ret; | ||
479 | |||
480 | /* Figure out the PE address */ | ||
481 | edev = of_node_to_eeh_dev(dn); | ||
482 | config_addr = edev->config_addr; | ||
483 | if (edev->pe_config_addr) | ||
484 | config_addr = edev->pe_config_addr; | ||
485 | |||
486 | /* Use new configure-pe function, if supported */ | ||
487 | if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { | ||
488 | ret = rtas_call(ibm_configure_pe, 3, 1, NULL, | ||
489 | config_addr, BUID_HI(edev->phb->buid), | ||
490 | BUID_LO(edev->phb->buid)); | ||
491 | } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { | ||
492 | ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, | ||
493 | config_addr, BUID_HI(edev->phb->buid), | ||
494 | BUID_LO(edev->phb->buid)); | ||
495 | } else { | ||
496 | return -EFAULT; | ||
497 | } | ||
498 | |||
499 | if (ret) | ||
500 | pr_warning("%s: Unable to configure bridge %d for %s\n", | ||
501 | __func__, ret, dn->full_name); | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * pseries_eeh_read_config - Read PCI config space | ||
508 | * @dn: device node | ||
509 | * @where: PCI address | ||
510 | * @size: size to read | ||
511 | * @val: return value | ||
512 | * | ||
513 | * Read config space from the speicifed device | ||
514 | */ | ||
515 | static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val) | ||
516 | { | ||
517 | struct pci_dn *pdn; | ||
518 | |||
519 | pdn = PCI_DN(dn); | ||
520 | |||
521 | return rtas_read_config(pdn, where, size, val); | ||
522 | } | ||
523 | |||
524 | /** | ||
525 | * pseries_eeh_write_config - Write PCI config space | ||
526 | * @dn: device node | ||
527 | * @where: PCI address | ||
528 | * @size: size to write | ||
529 | * @val: value to be written | ||
530 | * | ||
531 | * Write config space to the specified device | ||
532 | */ | ||
533 | static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val) | ||
534 | { | ||
535 | struct pci_dn *pdn; | ||
536 | |||
537 | pdn = PCI_DN(dn); | ||
538 | |||
539 | return rtas_write_config(pdn, where, size, val); | ||
540 | } | ||
541 | |||
542 | static struct eeh_ops pseries_eeh_ops = { | ||
543 | .name = "pseries", | ||
544 | .init = pseries_eeh_init, | ||
545 | .set_option = pseries_eeh_set_option, | ||
546 | .get_pe_addr = pseries_eeh_get_pe_addr, | ||
547 | .get_state = pseries_eeh_get_state, | ||
548 | .reset = pseries_eeh_reset, | ||
549 | .wait_state = pseries_eeh_wait_state, | ||
550 | .get_log = pseries_eeh_get_log, | ||
551 | .configure_bridge = pseries_eeh_configure_bridge, | ||
552 | .read_config = pseries_eeh_read_config, | ||
553 | .write_config = pseries_eeh_write_config | ||
554 | }; | ||
555 | |||
556 | /** | ||
557 | * eeh_pseries_init - Register platform dependent EEH operations | ||
558 | * | ||
559 | * EEH initialization on pseries platform. This function should be | ||
560 | * called before any EEH related functions. | ||
561 | */ | ||
562 | int __init eeh_pseries_init(void) | ||
563 | { | ||
564 | return eeh_ops_register(&pseries_eeh_ops); | ||
565 | } | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c index eb744ee234da..243b3510d70f 100644 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include <asm/pci-bridge.h> | 28 | #include <asm/pci-bridge.h> |
29 | 29 | ||
30 | /** | 30 | /** |
31 | * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic | 31 | * EEH_SHOW_ATTR -- Create sysfs entry for eeh statistic |
32 | * @_name: name of file in sysfs directory | 32 | * @_name: name of file in sysfs directory |
33 | * @_memb: name of member in struct pci_dn to access | 33 | * @_memb: name of member in struct pci_dn to access |
34 | * @_format: printf format for display | 34 | * @_format: printf format for display |
@@ -41,24 +41,21 @@ static ssize_t eeh_show_##_name(struct device *dev, \ | |||
41 | struct device_attribute *attr, char *buf) \ | 41 | struct device_attribute *attr, char *buf) \ |
42 | { \ | 42 | { \ |
43 | struct pci_dev *pdev = to_pci_dev(dev); \ | 43 | struct pci_dev *pdev = to_pci_dev(dev); \ |
44 | struct device_node *dn = pci_device_to_OF_node(pdev); \ | 44 | struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev); \ |
45 | struct pci_dn *pdn; \ | ||
46 | \ | 45 | \ |
47 | if (!dn || PCI_DN(dn) == NULL) \ | 46 | if (!edev) \ |
48 | return 0; \ | 47 | return 0; \ |
49 | \ | 48 | \ |
50 | pdn = PCI_DN(dn); \ | 49 | return sprintf(buf, _format "\n", edev->_memb); \ |
51 | return sprintf(buf, _format "\n", pdn->_memb); \ | ||
52 | } \ | 50 | } \ |
53 | static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); | 51 | static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); |
54 | 52 | ||
55 | 53 | EEH_SHOW_ATTR(eeh_mode, mode, "0x%x"); | |
56 | EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x"); | 54 | EEH_SHOW_ATTR(eeh_config_addr, config_addr, "0x%x"); |
57 | EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x"); | 55 | EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x"); |
58 | EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x"); | 56 | EEH_SHOW_ATTR(eeh_check_count, check_count, "%d" ); |
59 | EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d"); | 57 | EEH_SHOW_ATTR(eeh_freeze_count, freeze_count, "%d" ); |
60 | EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d"); | 58 | EEH_SHOW_ATTR(eeh_false_positives, false_positives, "%d" ); |
61 | EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d"); | ||
62 | 59 | ||
63 | void eeh_sysfs_add_device(struct pci_dev *pdev) | 60 | void eeh_sysfs_add_device(struct pci_dev *pdev) |
64 | { | 61 | { |
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 38d24e7e7bb1..109fdb75578d 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c | |||
@@ -217,7 +217,7 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) | |||
217 | if (!dn) | 217 | if (!dn) |
218 | return NULL; | 218 | return NULL; |
219 | 219 | ||
220 | dn = find_device_pe(dn); | 220 | dn = eeh_find_device_pe(dn); |
221 | if (!dn) | 221 | if (!dn) |
222 | return NULL; | 222 | return NULL; |
223 | 223 | ||
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 d928412cfb32..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; |
@@ -381,6 +385,7 @@ static void __init pSeries_setup_arch(void) | |||
381 | 385 | ||
382 | /* Find and initialize PCI host bridges */ | 386 | /* Find and initialize PCI host bridges */ |
383 | init_pci_config_tokens(); | 387 | init_pci_config_tokens(); |
388 | eeh_pseries_init(); | ||
384 | find_and_init_phbs(); | 389 | find_and_init_phbs(); |
385 | pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); | 390 | pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); |
386 | eeh_init(); | 391 | eeh_init(); |