Commit 9353154e authored by Paul Mackerras's avatar Paul Mackerras Committed by Linus Torvalds

[PATCH] ppc64: EEH fixes for POWER5 machines (1/2)

From: Linas Vepstas <linas@austin.ibm.com>

This patch allows ppc64 to boot on Power5 machines.  The new Power5 PCI
bridge design requires EEH (enhanced PCI error handling) to be enabled for
all PCI devices, not just some PCI devices.  In addition, this patch moves
the check for PCI to ISA bridges out of perf critical code, and into
initialization code.  This also avoids race conditions where the device
type might not have been set.  Also, some whitespace fixes, and some
error-message-printing beautification.
Signed-off-by: default avatarLinas Vepstas <linas@linas.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d1ae0015
...@@ -397,12 +397,6 @@ unsigned long eeh_check_failure(void *token, unsigned long val) ...@@ -397,12 +397,6 @@ unsigned long eeh_check_failure(void *token, unsigned long val)
return val; return val;
} }
/* Make sure we aren't ISA */
if (!strcmp(dn->type, "isa")) {
pci_dev_put(dev);
return val;
}
if (!dn->eeh_config_addr) { if (!dn->eeh_config_addr) {
pci_dev_put(dev); pci_dev_put(dev);
return val; return val;
...@@ -465,6 +459,7 @@ EXPORT_SYMBOL(eeh_check_failure); ...@@ -465,6 +459,7 @@ EXPORT_SYMBOL(eeh_check_failure);
struct eeh_early_enable_info { struct eeh_early_enable_info {
unsigned int buid_hi; unsigned int buid_hi;
unsigned int buid_lo; unsigned int buid_lo;
int force_off;
}; };
/* Enable eeh for the given device node. */ /* Enable eeh for the given device node. */
...@@ -479,6 +474,8 @@ static void *early_enable_eeh(struct device_node *dn, void *data) ...@@ -479,6 +474,8 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
u32 *regs; u32 *regs;
int enable; int enable;
dn->eeh_mode = 0;
if (status && strcmp(status, "ok") != 0) if (status && strcmp(status, "ok") != 0)
return NULL; /* ignore devices with bad status */ return NULL; /* ignore devices with bad status */
...@@ -492,6 +489,12 @@ static void *early_enable_eeh(struct device_node *dn, void *data) ...@@ -492,6 +489,12 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
*device_id == 0x0188 || *device_id == 0x0302)) *device_id == 0x0188 || *device_id == 0x0302))
return NULL; return NULL;
/* There is nothing to check on PCI to ISA bridges */
if (dn->type && !strcmp(dn->type, "isa")) {
dn->eeh_mode |= EEH_MODE_NOCHECK;
return NULL;
}
/* /*
* Now decide if we are going to "Disable" EEH checking * Now decide if we are going to "Disable" EEH checking
* for this device. We still run with the EEH hardware active, * for this device. We still run with the EEH hardware active,
...@@ -508,12 +511,12 @@ static void *early_enable_eeh(struct device_node *dn, void *data) ...@@ -508,12 +511,12 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
enable)) { enable)) {
if (enable) { if (enable) {
printk(KERN_WARNING "EEH: %s user requested to run " printk(KERN_WARNING "EEH: %s user requested to run "
"without EEH.\n", dn->full_name); "without EEH checking.\n", dn->full_name);
enable = 0; enable = 0;
} }
} }
if (!enable) { if (!enable || info->force_off) {
dn->eeh_mode = EEH_MODE_NOCHECK; dn->eeh_mode = EEH_MODE_NOCHECK;
return NULL; return NULL;
} }
...@@ -543,8 +546,8 @@ static void *early_enable_eeh(struct device_node *dn, void *data) ...@@ -543,8 +546,8 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
dn->full_name); dn->full_name);
#endif #endif
} else { } else {
printk(KERN_WARNING "EEH: %s: could not enable EEH, rtas_call failed.\n", printk(KERN_WARNING "EEH: %s: could not enable EEH, rtas_call failed; rc=%d\n",
dn->full_name); dn->full_name, ret);
} }
} else { } else {
printk(KERN_WARNING "EEH: %s: unable to get reg property.\n", printk(KERN_WARNING "EEH: %s: unable to get reg property.\n",
...@@ -570,10 +573,18 @@ static void *early_enable_eeh(struct device_node *dn, void *data) ...@@ -570,10 +573,18 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
*/ */
void __init eeh_init(void) void __init eeh_init(void)
{ {
struct device_node *phb; struct device_node *phb, *np;
struct eeh_early_enable_info info; struct eeh_early_enable_info info;
char *eeh_force_off = strstr(saved_command_line, "eeh-force-off"); char *eeh_force_off = strstr(saved_command_line, "eeh-force-off");
init_pci_config_tokens();
np = of_find_node_by_path("/rtas");
if (np == NULL) {
printk(KERN_WARNING "EEH: RTAS not found !\n");
return;
}
ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
...@@ -581,14 +592,14 @@ void __init eeh_init(void) ...@@ -581,14 +592,14 @@ void __init eeh_init(void)
if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
return; return;
info.force_off = 0;
if (eeh_force_off) { if (eeh_force_off) {
printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error " printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error "
"Handling is user disabled\n"); "Handling is user disabled\n");
return; info.force_off = 1;
} }
/* Enable EEH for all adapters. Note that eeh requires buid's */ /* Enable EEH for all adapters. Note that eeh requires buid's */
init_pci_config_tokens();
for (phb = of_find_node_by_name(NULL, "pci"); phb; for (phb = of_find_node_by_name(NULL, "pci"); phb;
phb = of_find_node_by_name(phb, "pci")) { phb = of_find_node_by_name(phb, "pci")) {
unsigned long buid; unsigned long buid;
...@@ -602,8 +613,11 @@ void __init eeh_init(void) ...@@ -602,8 +613,11 @@ void __init eeh_init(void)
traverse_pci_devices(phb, early_enable_eeh, NULL, &info); traverse_pci_devices(phb, early_enable_eeh, NULL, &info);
} }
if (eeh_subsystem_enabled) if (eeh_subsystem_enabled) {
printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n"); printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n");
} else {
printk(KERN_WARNING "EEH: disabled PCI Enhanced I/O Error Handling\n");
}
} }
/** /**
...@@ -743,10 +757,10 @@ static int proc_eeh_open(struct inode *inode, struct file *file) ...@@ -743,10 +757,10 @@ static int proc_eeh_open(struct inode *inode, struct file *file)
} }
static struct file_operations proc_eeh_operations = { static struct file_operations proc_eeh_operations = {
.open = proc_eeh_open, .open = proc_eeh_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = single_release, .release = single_release,
}; };
static int __init eeh_init_proc(void) static int __init eeh_init_proc(void)
...@@ -759,7 +773,7 @@ static int __init eeh_init_proc(void) ...@@ -759,7 +773,7 @@ static int __init eeh_init_proc(void)
e->proc_fops = &proc_eeh_operations; e->proc_fops = &proc_eeh_operations;
} }
return 0; return 0;
} }
__initcall(eeh_init_proc); __initcall(eeh_init_proc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment