diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/eeh.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh.c | 54 |
1 files changed, 31 insertions, 23 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index b8770395013d..22322b35a0ff 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -169,6 +169,8 @@ static void rtas_slot_error_detail(struct pci_dn *pdn, int severity, | |||
169 | */ | 169 | */ |
170 | static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | 170 | static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) |
171 | { | 171 | { |
172 | struct device_node *dn; | ||
173 | struct pci_dev *dev = pdn->pcidev; | ||
172 | u32 cfg; | 174 | u32 cfg; |
173 | int cap, i; | 175 | int cap, i; |
174 | int n = 0; | 176 | int n = 0; |
@@ -184,6 +186,17 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
184 | n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); | 186 | n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); |
185 | printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); | 187 | printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); |
186 | 188 | ||
189 | /* Gather bridge-specific registers */ | ||
190 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { | ||
191 | rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg); | ||
192 | n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); | ||
193 | printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); | ||
194 | |||
195 | rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg); | ||
196 | n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); | ||
197 | printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); | ||
198 | } | ||
199 | |||
187 | /* Dump out the PCI-X command and status regs */ | 200 | /* Dump out the PCI-X command and status regs */ |
188 | cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_PCIX); | 201 | cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_PCIX); |
189 | if (cap) { | 202 | if (cap) { |
@@ -209,7 +222,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
209 | printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); | 222 | printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); |
210 | } | 223 | } |
211 | 224 | ||
212 | cap = pci_find_ext_capability(pdn->pcidev,PCI_EXT_CAP_ID_ERR); | 225 | cap = pci_find_ext_capability(pdn->pcidev, PCI_EXT_CAP_ID_ERR); |
213 | if (cap) { | 226 | if (cap) { |
214 | n += scnprintf(buf+n, len-n, "pci-e AER:\n"); | 227 | n += scnprintf(buf+n, len-n, "pci-e AER:\n"); |
215 | printk(KERN_WARNING | 228 | printk(KERN_WARNING |
@@ -222,6 +235,18 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
222 | } | 235 | } |
223 | } | 236 | } |
224 | } | 237 | } |
238 | |||
239 | /* Gather status on devices under the bridge */ | ||
240 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { | ||
241 | dn = pdn->node->child; | ||
242 | while (dn) { | ||
243 | pdn = PCI_DN(dn); | ||
244 | if (pdn) | ||
245 | n += gather_pci_data(pdn, buf+n, len-n); | ||
246 | dn = dn->sibling; | ||
247 | } | ||
248 | } | ||
249 | |||
225 | return n; | 250 | return n; |
226 | } | 251 | } |
227 | 252 | ||
@@ -750,12 +775,12 @@ int rtas_set_slot_reset(struct pci_dn *pdn) | |||
750 | return 0; | 775 | return 0; |
751 | 776 | ||
752 | if (rc < 0) { | 777 | if (rc < 0) { |
753 | printk (KERN_ERR "EEH: unrecoverable slot failure %s\n", | 778 | printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", |
754 | pdn->node->full_name); | 779 | pdn->node->full_name); |
755 | return -1; | 780 | return -1; |
756 | } | 781 | } |
757 | printk (KERN_ERR "EEH: bus reset %d failed on slot %s\n", | 782 | printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", |
758 | i+1, pdn->node->full_name); | 783 | i+1, pdn->node->full_name, rc); |
759 | } | 784 | } |
760 | 785 | ||
761 | return -1; | 786 | return -1; |
@@ -930,7 +955,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
930 | pdn->eeh_freeze_count = 0; | 955 | pdn->eeh_freeze_count = 0; |
931 | pdn->eeh_false_positives = 0; | 956 | pdn->eeh_false_positives = 0; |
932 | 957 | ||
933 | if (status && strcmp(status, "ok") != 0) | 958 | if (status && strncmp(status, "ok", 2) != 0) |
934 | return NULL; /* ignore devices with bad status */ | 959 | return NULL; /* ignore devices with bad status */ |
935 | 960 | ||
936 | /* Ignore bad nodes. */ | 961 | /* Ignore bad nodes. */ |
@@ -944,23 +969,6 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
944 | } | 969 | } |
945 | pdn->class_code = *class_code; | 970 | pdn->class_code = *class_code; |
946 | 971 | ||
947 | /* | ||
948 | * Now decide if we are going to "Disable" EEH checking | ||
949 | * for this device. We still run with the EEH hardware active, | ||
950 | * but we won't be checking for ff's. This means a driver | ||
951 | * could return bad data (very bad!), an interrupt handler could | ||
952 | * hang waiting on status bits that won't change, etc. | ||
953 | * But there are a few cases like display devices that make sense. | ||
954 | */ | ||
955 | enable = 1; /* i.e. we will do checking */ | ||
956 | #if 0 | ||
957 | if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY) | ||
958 | enable = 0; | ||
959 | #endif | ||
960 | |||
961 | if (!enable) | ||
962 | pdn->eeh_mode |= EEH_MODE_NOCHECK; | ||
963 | |||
964 | /* Ok... see if this device supports EEH. Some do, some don't, | 972 | /* Ok... see if this device supports EEH. Some do, some don't, |
965 | * and the only way to find out is to check each and every one. */ | 973 | * and the only way to find out is to check each and every one. */ |
966 | regs = of_get_property(dn, "reg", NULL); | 974 | regs = of_get_property(dn, "reg", NULL); |