From c73fcc846c91f53fd2c67fd9c6c04888a9e5892e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 20 Jul 2007 16:59:26 -0700 Subject: [SPARC]: Fix serial console device detection. The current scheme works on static interpretation of text names, which is wrong. The output-device setting, for example, must be resolved via an alias or similar to a full path name to the console device. Paths also contain an optional set of 'options', which starts with a colon at the end of the path. The option area is used to specify which of two serial ports ('a' or 'b') the path refers to when a device node drives multiple ports. 'a' is assumed if the option specification is missing. This was caught by the UltraSPARC-T1 simulator. The 'output-device' property was set to 'ttya' and we didn't pick upon the fact that this is an OBP alias set to '/virtual-devices/console'. Instead we saw it as the first serial console device, instead of the hypervisor console. The infrastructure is now there to take advantage of this to resolve the console correctly even in multi-head situations in fbcon too. Thanks to Greg Onufer for the bug report. Signed-off-by: David S. Miller --- arch/sparc/kernel/process.c | 8 ++- arch/sparc/kernel/prom.c | 131 ++++++++++++++++++++++++++++++++++++ arch/sparc/kernel/setup.c | 65 +----------------- arch/sparc/prom/console.c | 116 ------------------------------- arch/sparc/prom/misc.c | 4 +- arch/sparc64/kernel/power.c | 2 +- arch/sparc64/kernel/process.c | 6 +- arch/sparc64/kernel/prom.c | 56 +++++++++++++++ arch/sparc64/kernel/setup.c | 70 +------------------ arch/sparc64/kernel/sparc64_ksyms.c | 1 - arch/sparc64/prom/console.c | 85 ----------------------- arch/sparc64/prom/misc.c | 4 +- arch/sparc64/prom/tree.c | 8 +++ drivers/serial/suncore.c | 123 +++++++++++++-------------------- drivers/serial/suncore.h | 2 + drivers/serial/sunhv.c | 13 +--- drivers/serial/sunsab.c | 22 ++---- drivers/serial/sunsu.c | 23 ++----- drivers/serial/sunzilog.c | 24 ++----- drivers/video/aty/atyfb_base.c | 4 -- drivers/video/igafb.c | 4 -- include/asm-sparc/oplib.h | 26 ------- include/asm-sparc/prom.h | 4 ++ include/asm-sparc64/oplib.h | 28 +------- include/asm-sparc64/prom.h | 4 ++ include/asm-sparc64/system.h | 6 -- 26 files changed, 285 insertions(+), 554 deletions(-) diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 8c37f8f5adb..33f7a3ddb10 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -39,6 +39,7 @@ #include #include #include +#include #include /* @@ -150,7 +151,7 @@ void machine_halt(void) local_irq_enable(); mdelay(8); local_irq_disable(); - if (!serial_console && prom_palette) + if (prom_palette) prom_palette (1); prom_halt(); panic("Halt failed!"); @@ -166,7 +167,7 @@ void machine_restart(char * cmd) p = strchr (reboot_command, '\n'); if (p) *p = 0; - if (!serial_console && prom_palette) + if (prom_palette) prom_palette (1); if (cmd) prom_reboot(cmd); @@ -179,7 +180,8 @@ void machine_restart(char * cmd) void machine_power_off(void) { #ifdef CONFIG_SUN_AUXIO - if (auxio_power_register && (!serial_console || scons_pwroff)) + if (auxio_power_register && + (strcmp(of_console_device->type, "serial") || scons_pwroff)) *auxio_power_register |= AUXIO_POWER_OFF; #endif machine_halt(); diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 012f98346bc..e3a537650db 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -397,6 +397,135 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl return dp; } +struct device_node *of_console_device; +EXPORT_SYMBOL(of_console_device); + +char *of_console_path; +EXPORT_SYMBOL(of_console_path); + +char *of_console_options; +EXPORT_SYMBOL(of_console_options); + +extern void restore_current(void); + +static void __init of_console_init(void) +{ + char *msg = "OF stdout device is: %s\n"; + struct device_node *dp; + unsigned long flags; + const char *type; + phandle node; + int skip, fd; + + of_console_path = prom_early_alloc(256); + + switch (prom_vers) { + case PROM_V0: + case PROM_SUN4: + skip = 0; + switch (*romvec->pv_stdout) { + case PROMDEV_SCREEN: + type = "display"; + break; + + case PROMDEV_TTYB: + skip = 1; + /* FALLTHRU */ + + case PROMDEV_TTYA: + type = "serial"; + break; + + default: + prom_printf("Invalid PROM_V0 stdout value %u\n", + *romvec->pv_stdout); + prom_halt(); + } + + for_each_node_by_type(dp, type) { + if (!skip--) + break; + } + if (!dp) { + prom_printf("Cannot find PROM_V0 console node.\n"); + prom_halt(); + } + of_console_device = dp; + + strcpy(of_console_path, dp->full_name); + if (!strcmp(type, "serial")) { + strcat(of_console_path, + (skip ? ":b" : ":a")); + } + break; + + default: + case PROM_V2: + case PROM_V3: + fd = *romvec->pv_v2bootargs.fd_stdout; + + spin_lock_irqsave(&prom_lock, flags); + node = (*romvec->pv_v2devops.v2_inst2pkg)(fd); + restore_current(); + spin_unlock_irqrestore(&prom_lock, flags); + + if (!node) { + prom_printf("Cannot resolve stdout node from " + "instance %08x.\n", fd); + prom_halt(); + } + dp = of_find_node_by_phandle(node); + type = of_get_property(dp, "device_type", NULL); + + if (!type) { + prom_printf("Console stdout lacks " + "device_type property.\n"); + prom_halt(); + } + + if (strcmp(type, "display") && strcmp(type, "serial")) { + prom_printf("Console device_type is neither display " + "nor serial.\n"); + prom_halt(); + } + + of_console_device = dp; + + if (prom_vers == PROM_V2) { + strcpy(of_console_path, dp->full_name); + switch (*romvec->pv_stdout) { + case PROMDEV_TTYA: + strcat(of_console_path, ":a"); + break; + case PROMDEV_TTYB: + strcat(of_console_path, ":b"); + break; + } + } else { + const char *path; + + dp = of_find_node_by_path("/"); + path = of_get_property(dp, "stdout-path", NULL); + if (!path) { + prom_printf("No stdout-path in root node.\n"); + prom_halt(); + } + strcpy(of_console_path, path); + } + break; + } + + of_console_options = strrchr(of_console_path, ':'); + if (of_console_options) { + of_console_options++; + if (*of_console_options == '\0') + of_console_options = NULL; + } + + prom_printf(msg, of_console_path); + printk(msg, of_console_path); +} + void __init prom_build_devicetree(void) { struct device_node **nextp; @@ -409,6 +538,8 @@ void __init prom_build_devicetree(void) allnodes->child = build_tree(allnodes, prom_getchild(allnodes->node), &nextp); + of_console_init(); + printk("PROM: Built device tree with %u bytes of memory.\n", prom_early_allocated); } diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 64c0ed98820..f8228383895 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -146,31 +146,6 @@ static void __init process_switch(char c) } } -static void __init process_console(char *commands) -{ - serial_console = 0; - commands += 8; - /* Linux-style serial */ - if (!strncmp(commands, "ttyS", 4)) - serial_console = simple_strtoul(commands + 4, NULL, 10) + 1; - else if (!strncmp(commands, "tty", 3)) { - char c = *(commands + 3); - /* Solaris-style serial */ - if (c == 'a' || c == 'b') - serial_console = c - 'a' + 1; - /* else Linux-style fbcon, not serial */ - } -#if defined(CONFIG_PROM_CONSOLE) - if (!strncmp(commands, "prom", 4)) { - char *p; - - for (p = commands - 8; *p && *p != ' '; p++) - *p = ' '; - conswitchp = &prom_con; - } -#endif -} - static void __init boot_flags_init(char *commands) { while (*commands) { @@ -187,9 +162,7 @@ static void __init boot_flags_init(char *commands) process_switch(*commands++); continue; } - if (!strncmp(commands, "console=", 8)) { - process_console(commands); - } else if (!strncmp(commands, "mem=", 4)) { + if (!strncmp(commands, "mem=", 4)) { /* * "mem=XXX[kKmM] overrides the PROM-reported * memory size. @@ -341,41 +314,6 @@ void __init setup_arch(char **cmdline_p) smp_setup_cpu_possible_map(); } -static int __init set_preferred_console(void) -{ - int idev, odev; - - /* The user has requested a console so this is already set up. */ - if (serial_console >= 0) - return -EBUSY; - - idev = prom_query_input_device(); - odev = prom_query_output_device(); - if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { - serial_console = 0; - } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { - serial_console = 1; - } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { - serial_console = 2; - } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) { - prom_printf("MrCoffee ttya\n"); - serial_console = 1; - } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) { - serial_console = 0; - prom_printf("MrCoffee keyboard\n"); - } else { - prom_printf("Confusing console (idev %d, odev %d)\n", - idev, odev); - serial_console = 1; - } - - if (serial_console) - return add_preferred_console("ttyS", serial_console - 1, NULL); - - return -ENODEV; -} -console_initcall(set_preferred_console); - extern char *sparc_cpu_type; extern char *sparc_fpu_type; @@ -461,7 +399,6 @@ void sun_do_break(void) prom_cmdline(); } -int serial_console = -1; int stop_a_enabled = 1; static int __init topology_init(void) diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c index 4e6e41d3291..8d1cfb0d506 100644 --- a/arch/sparc/prom/console.c +++ b/arch/sparc/prom/console.c @@ -102,119 +102,3 @@ prom_putchar(char c) while(prom_nbputchar(c) == -1) ; return; } - -/* Query for input device type */ -enum prom_input_device -prom_query_input_device(void) -{ - unsigned long flags; - int st_p; - char propb[64]; - char *p; - int propl; - - switch(prom_vers) { - case PROM_V0: - case PROM_V2: - case PROM_SUN4: - default: - switch(*romvec->pv_stdin) { - case PROMDEV_KBD: return PROMDEV_IKBD; - case PROMDEV_TTYA: return PROMDEV_ITTYA; - case PROMDEV_TTYB: return PROMDEV_ITTYB; - default: - return PROMDEV_I_UNK; - }; - case PROM_V3: - spin_lock_irqsave(&prom_lock, flags); - st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin); - restore_current(); - spin_unlock_irqrestore(&prom_lock, flags); - if(prom_node_has_property(st_p, "keyboard")) - return PROMDEV_IKBD; - if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) { - if(strncmp(propb, "keyboard", sizeof("serial")) == 0) - return PROMDEV_IKBD; - } - if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) { - if(strncmp(propb, "serial", sizeof("serial"))) - return PROMDEV_I_UNK; - } - propl = prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb)); - if(propl > 2) { - p = propb; - while(*p) p++; p -= 2; - if(p[0] == ':') { - if(p[1] == 'a') - return PROMDEV_ITTYA; - else if(p[1] == 'b') - return PROMDEV_ITTYB; - } - } - return PROMDEV_I_UNK; - } -} - -/* Query for output device type */ - -enum prom_output_device -prom_query_output_device(void) -{ - unsigned long flags; - int st_p; - char propb[64]; - char *p; - int propl; - - switch(prom_vers) { - case PROM_V0: - case PROM_SUN4: - switch(*romvec->pv_stdin) { - case PROMDEV_SCREEN: return PROMDEV_OSCREEN; - case PROMDEV_TTYA: return PROMDEV_OTTYA; - case PROMDEV_TTYB: return PROMDEV_OTTYB; - }; - break; - case PROM_V2: - case PROM_V3: - spin_lock_irqsave(&prom_lock, flags); - st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout); - restore_current(); - spin_unlock_irqrestore(&prom_lock, flags); - propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); - if (propl == sizeof("display") && - strncmp("display", propb, sizeof("display")) == 0) - { - return PROMDEV_OSCREEN; - } - if(prom_vers == PROM_V3) { - if(propl >= 0 && - strncmp("serial", propb, sizeof("serial")) != 0) - return PROMDEV_O_UNK; - propl = prom_getproperty(prom_root_node, "stdout-path", - propb, sizeof(propb)); - if(propl == CON_SIZE_JMC && - strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0) - return PROMDEV_OTTYA; - if(propl > 2) { - p = propb; - while(*p) p++; p-= 2; - if(p[0]==':') { - if(p[1] == 'a') - return PROMDEV_OTTYA; - else if(p[1] == 'b') - return PROMDEV_OTTYB; - } - } - } else { - switch(*romvec->pv_stdin) { - case PROMDEV_TTYA: return PROMDEV_OTTYA; - case PROMDEV_TTYB: return PROMDEV_OTTYB; - }; - } - break; - default: - ; - }; - return PROMDEV_O_UNK; -} diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c index 1942c7c05cb..37cff5f5470 100644 --- a/arch/sparc/prom/misc.c +++ b/arch/sparc/prom/misc.c @@ -58,7 +58,7 @@ prom_cmdline(void) extern void install_linux_ticker(void); unsigned long flags; - if(!serial_console && prom_palette) + if (prom_palette) prom_palette (1); spin_lock_irqsave(&prom_lock, flags); install_obp_ticker(); @@ -69,7 +69,7 @@ prom_cmdline(void) #ifdef CONFIG_SUN_AUXIO set_auxio(AUXIO_LED, 0); #endif - if(!serial_console && prom_palette) + if (prom_palette) prom_palette (0); } diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index b00feb01c16..881a09ee4c4 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -46,7 +46,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off; void machine_power_off(void) { sstate_poweroff(); - if (!serial_console || scons_pwroff) { + if (strcmp(of_console_device->type, "serial") || scons_pwroff) { if (power_reg) { /* Both register bits seem to have the * same effect, so until I figure out diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 93557507ec9..fd7899ba1d7 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -119,7 +119,7 @@ extern void (*prom_keyboard)(void); void machine_halt(void) { sstate_halt(); - if (!serial_console && prom_palette) + if (prom_palette) prom_palette (1); if (prom_keyboard) prom_keyboard(); @@ -130,7 +130,7 @@ void machine_halt(void) void machine_alt_power_off(void) { sstate_poweroff(); - if (!serial_console && prom_palette) + if (prom_palette) prom_palette(1); if (prom_keyboard) prom_keyboard(); @@ -145,7 +145,7 @@ void machine_restart(char * cmd) sstate_reboot(); p = strchr (reboot_command, '\n'); if (p) *p = 0; - if (!serial_console && prom_palette) + if (prom_palette) prom_palette (1); if (prom_keyboard) prom_keyboard(); diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 2b2017ce226..f4e0a9ad9be 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -1646,6 +1646,60 @@ static void __init of_fill_in_cpu_data(void) smp_fill_in_sib_core_maps(); } +struct device_node *of_console_device; +EXPORT_SYMBOL(of_console_device); + +char *of_console_path; +EXPORT_SYMBOL(of_console_path); + +char *of_console_options; +EXPORT_SYMBOL(of_console_options); + +static void __init of_console_init(void) +{ + char *msg = "OF stdout device is: %s\n"; + struct device_node *dp; + const char *type; + phandle node; + + of_console_path = prom_early_alloc(256); + if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) { + prom_printf("Cannot obtain path of stdout.\n"); + prom_halt(); + } + of_console_options = strrchr(of_console_path, ':'); + if (of_console_options) { + of_console_options++; + if (*of_console_options == '\0') + of_console_options = NULL; + } + + node = prom_inst2pkg(prom_stdout); + if (!node) { + prom_printf("Cannot resolve stdout node from " + "instance %08x.\n", prom_stdout); + prom_halt(); + } + + dp = of_find_node_by_phandle(node); + type = of_get_property(dp, "device_type", NULL); + if (!type) { + prom_printf("Console stdout lacks device_type property.\n"); + prom_halt(); + } + + if (strcmp(type, "display") && strcmp(type, "serial")) { + prom_printf("Console device_type is neither display " + "nor serial.\n"); + prom_halt(); + } + + of_console_device = dp; + + prom_printf(msg, of_console_path); + printk(msg, of_console_path); +} + void __init prom_build_devicetree(void) { struct device_node **nextp; @@ -1658,6 +1712,8 @@ void __init prom_build_devicetree(void) allnodes->child = build_tree(allnodes, prom_getchild(allnodes->node), &nextp); + of_console_init(); + printk("PROM: Built device tree with %u bytes of memory.\n", prom_early_allocated); diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index aafde3dd9fd..0f5be828ee9 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -133,33 +133,6 @@ static void __init process_switch(char c) } } -static void __init process_console(char *commands) -{ - serial_console = 0; - commands += 8; - /* Linux-style serial */ - if (!strncmp(commands, "ttyS", 4)) - serial_console = simple_strtoul(commands + 4, NULL, 10) + 1; - else if (!strncmp(commands, "tty", 3)) { - char c = *(commands + 3); - /* Solaris-style serial */ - if (c == 'a' || c == 'b') { - serial_console = c - 'a' + 1; - prom_printf ("Using /dev/tty%c as console.\n", c); - } - /* else Linux-style fbcon, not serial */ - } -#if defined(CONFIG_PROM_CONSOLE) - if (!strncmp(commands, "prom", 4)) { - char *p; - - for (p = commands - 8; *p && *p != ' '; p++) - *p = ' '; - conswitchp = &prom_con; - } -#endif -} - static void __init boot_flags_init(char *commands) { while (*commands) { @@ -176,9 +149,7 @@ static void __init boot_flags_init(char *commands) process_switch(*commands++); continue; } - if (!strncmp(commands, "console=", 8)) { - process_console(commands); - } else if (!strncmp(commands, "mem=", 4)) { + if (!strncmp(commands, "mem=", 4)) { /* * "mem=XXX[kKmM]" overrides the PROM-reported * memory size. @@ -378,44 +349,6 @@ void __init setup_arch(char **cmdline_p) paging_init(); } -static int __init set_preferred_console(void) -{ - int idev, odev; - - /* The user has requested a console so this is already set up. */ - if (serial_console >= 0) - return -EBUSY; - - idev = prom_query_input_device(); - odev = prom_query_output_device(); - if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { - serial_console = 0; - } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { - serial_console = 1; - } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { - serial_console = 2; - } else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) { - serial_console = 3; - } else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) { - /* sunhv_console_init() doesn't check the serial_console - * value anyways... - */ - serial_console = 4; - return add_preferred_console("ttyHV", 0, NULL); - } else { - prom_printf("Inconsistent console: " - "input %d, output %d\n", - idev, odev); - prom_halt(); - } - - if (serial_console) - return add_preferred_console("ttyS", serial_console - 1, NULL); - - return -ENODEV; -} -console_initcall(set_preferred_console); - /* BUFFER is PAGE_SIZE bytes long. */ extern char *sparc_cpu_type; @@ -508,5 +441,4 @@ void sun_do_break(void) prom_cmdline(); } -int serial_console = -1; int stop_a_enabled = 1; diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 719d676c2dd..7d36531aa5b 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -330,7 +330,6 @@ EXPORT_SYMBOL(VISenter); /* for input/keybdev */ EXPORT_SYMBOL(sun_do_break); -EXPORT_SYMBOL(serial_console); EXPORT_SYMBOL(stop_a_enabled); #ifdef CONFIG_DEBUG_BUGVERBOSE diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c index 7c25c54cefd..3fafa9a8b50 100644 --- a/arch/sparc64/prom/console.c +++ b/arch/sparc64/prom/console.c @@ -73,88 +73,3 @@ prom_puts(const char *s, int len) P1275_INOUT(3,1), prom_stdout, s, P1275_SIZE(len)); } - -/* Query for input device type */ -enum prom_input_device -prom_query_input_device(void) -{ - int st_p; - char propb[64]; - - st_p = prom_inst2pkg(prom_stdin); - if(prom_node_has_property(st_p, "keyboard")) - return PROMDEV_IKBD; - prom_getproperty(st_p, "device_type", propb, sizeof(propb)); - if(strncmp(propb, "serial", 6)) - return PROMDEV_I_UNK; - /* FIXME: Is there any better way how to find out? */ - memset(propb, 0, sizeof(propb)); - st_p = prom_finddevice ("/options"); - prom_getproperty(st_p, "input-device", propb, sizeof(propb)); - - /* - * If we get here with propb == 'keyboard', we are on ttya, as - * the PROM defaulted to this due to 'no input device'. - */ - if (!strncmp(propb, "keyboard", 8)) - return PROMDEV_ITTYA; - - if (!strncmp (propb, "rsc", 3)) - return PROMDEV_IRSC; - - if (!strncmp (propb, "virtual-console", 3)) - return PROMDEV_IVCONS; - - if (strncmp (propb, "tty", 3) || !propb[3]) - return PROMDEV_I_UNK; - - switch (propb[3]) { - case 'a': return PROMDEV_ITTYA; - case 'b': return PROMDEV_ITTYB; - default: return PROMDEV_I_UNK; - } -} - -/* Query for output device type */ - -enum prom_output_device -prom_query_output_device(void) -{ - int st_p; - char propb[64]; - int propl; - - st_p = prom_inst2pkg(prom_stdout); - propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); - if (propl >= 0 && propl == sizeof("display") && - strncmp("display", propb, sizeof("display")) == 0) - return PROMDEV_OSCREEN; - if(strncmp("serial", propb, 6)) - return PROMDEV_O_UNK; - /* FIXME: Is there any better way how to find out? */ - memset(propb, 0, sizeof(propb)); - st_p = prom_finddevice ("/options"); - prom_getproperty(st_p, "output-device", propb, sizeof(propb)); - - /* - * If we get here with propb == 'screen', we are on ttya, as - * the PROM defaulted to this due to 'no input device'. - */ - if (!strncmp(propb, "screen", 6)) - return PROMDEV_OTTYA; - - if (!strncmp (propb, "rsc", 3)) - return PROMDEV_ORSC; - - if (!strncmp (propb, "virtual-console", 3)) - return PROMDEV_OVCONS; - - if (strncmp (propb, "tty", 3) || !propb[3]) - return PROMDEV_O_UNK; - - switch (propb[3]) { - case 'a': return PROMDEV_OTTYA; - case 'b': return PROMDEV_OTTYB; - default: return PROMDEV_O_UNK; - } -} diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 33c5b7da31e..68c83ad04ad 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -72,7 +72,7 @@ void prom_cmdline(void) local_irq_save(flags); - if (!serial_console && prom_palette) + if (prom_palette) prom_palette(1); #ifdef CONFIG_SMP @@ -85,7 +85,7 @@ void prom_cmdline(void) smp_release(); #endif - if (!serial_console && prom_palette) + if (prom_palette) prom_palette(0); local_irq_restore(flags); diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c index 17b7ecfe7ca..b2c5b12c981 100644 --- a/arch/sparc64/prom/tree.c +++ b/arch/sparc64/prom/tree.c @@ -304,3 +304,11 @@ prom_pathtoinode(const char *path) if (node == -1) return 0; return node; } + +int prom_ihandle2path(int handle, char *buffer, int bufsize) +{ + return p1275_cmd("instance-to-path", + P1275_ARG(1,P1275_ARG_OUT_BUF)| + P1275_INOUT(3, 1), + handle, buffer, P1275_SIZE(bufsize)); +} diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c index b45ba5392dd..70a09a3d5af 100644 --- a/drivers/serial/suncore.c +++ b/drivers/serial/suncore.c @@ -16,9 +16,10 @@ #include #include #include +#include #include -#include +#include #include "suncore.h" @@ -26,92 +27,60 @@ int sunserial_current_minor = 64; EXPORT_SYMBOL(sunserial_current_minor); -void -sunserial_console_termios(struct console *con) +int sunserial_console_match(struct console *con, struct device_node *dp, + struct uart_driver *drv, int line) { - char mode[16], buf[16], *s; - char mode_prop[] = "ttyX-mode"; - char cd_prop[] = "ttyX-ignore-cd"; - char dtr_prop[] = "ttyX-rts-dtr-off"; - char *ssp_console_modes_prop = "ssp-console-modes"; - int baud, bits, stop, cflag; - char parity; - int carrier = 0; - int rtsdtr = 1; - int topnd, nd; - - if (!serial_console) - return; - - switch (serial_console) { - case PROMDEV_OTTYA: - mode_prop[3] = 'a'; - cd_prop[3] = 'a'; - dtr_prop[3] = 'a'; - break; - - case PROMDEV_OTTYB: - mode_prop[3] = 'b'; - cd_prop[3] = 'b'; - dtr_prop[3] = 'b'; - break; - - case PROMDEV_ORSC: - - nd = prom_pathtoinode("rsc"); - if (!nd) { - strcpy(mode, "115200,8,n,1,-"); - goto no_options; - } + int off; - if (!prom_node_has_property(nd, ssp_console_modes_prop)) { - strcpy(mode, "115200,8,n,1,-"); - goto no_options; - } + if (!con || of_console_device != dp) + return 0; - memset(mode, 0, sizeof(mode)); - prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode)); - goto no_options; + off = 0; + if (of_console_options && + *of_console_options == 'b') + off = 1; - default: - strcpy(mode, "9600,8,n,1,-"); - goto no_options; - } + if ((line & 1) != off) + return 0; - topnd = prom_getchild(prom_root_node); - nd = prom_searchsiblings(topnd, "options"); - if (!nd) { - strcpy(mode, "9600,8,n,1,-"); - goto no_options; - } - - if (!prom_node_has_property(nd, mode_prop)) { - strcpy(mode, "9600,8,n,1,-"); - goto no_options; - } + con->index = line; + drv->cons = con; + add_preferred_console(con->name, line, NULL); - memset(mode, 0, sizeof(mode)); - prom_getstring(nd, mode_prop, mode, sizeof(mode)); - - if (prom_node_has_property(nd, cd_prop)) { - memset(buf, 0, sizeof(buf)); - prom_getstring(nd, cd_prop, buf, sizeof(buf)); - if (!strcmp(buf, "false")) - carrier = 1; - - /* XXX: this is unused below. */ - } + return 1; +} +EXPORT_SYMBOL(sunserial_console_match); - if (prom_node_has_property(nd, dtr_prop)) { - memset(buf, 0, sizeof(buf)); - prom_getstring(nd, dtr_prop, buf, sizeof(buf)); - if (!strcmp(buf, "false")) - rtsdtr = 0; +void +sunserial_console_termios(struct console *con) +{ + struct device_node *dp; + const char *od, *mode, *s; + char mode_prop[] = "ttyX-mode"; + int baud, bits, stop, cflag; + char parity; - /* XXX: this is unused below. */ + dp = of_find_node_by_path("/options"); + od = of_get_property(dp, "output-device", NULL); + if (!strcmp(od, "rsc")) { + mode = of_get_property(of_console_device, + "ssp-console-modes", NULL); + if (!mode) + mode = "115200,8,n,1,-"; + } else { + char c; + + c = 'a'; + if (of_console_options) + c = *of_console_options; + + mode_prop[3] = c; + + mode = of_get_property(dp, mode_prop, NULL); + if (!mode) + mode = "9600,8,n,1,-"; } -no_options: cflag = CREAD | HUPCL | CLOCAL; s = mode; diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h index 513916a8ce3..829d7d65d6d 100644 --- a/drivers/serial/suncore.h +++ b/drivers/serial/suncore.h @@ -24,6 +24,8 @@ extern int suncore_mouse_baud_detection(unsigned char, int); extern int sunserial_current_minor; +extern int sunserial_console_match(struct console *, struct device_node *, + struct uart_driver *, int); extern void sunserial_console_termios(struct console *); #endif /* !(_SERIAL_SUN_H) */ diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index d82be42ff29..8ff900b0981 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -520,16 +520,6 @@ static struct console sunhv_console = { .data = &sunhv_reg, }; -static inline struct console *SUNHV_CONSOLE(void) -{ - if (con_is_present()) - return NULL; - - sunhv_console.index = 0; - - return &sunhv_console; -} - static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match) { struct uart_port *port; @@ -582,7 +572,8 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; sunserial_current_minor += 1; - sunhv_reg.cons = SUNHV_CONSOLE(); + sunserial_console_match(&sunhv_console, op->node, + &sunhv_reg, port->line); err = uart_add_one_port(&sunhv_reg, port); if (err) diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 8a0f9e4408d..bca57bb9493 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -968,22 +968,6 @@ static struct console sunsab_console = { static inline struct console *SUNSAB_CONSOLE(void) { - int i; - - if (con_is_present()) - return NULL; - - for (i = 0; i < num_channels; i++) { - int this_minor = sunsab_reg.minor + i; - - if ((this_minor - 64) == (serial_console - 1)) - break; - } - if (i == num_channels) - return NULL; - - sunsab_console.index = i; - return &sunsab_console; } #else @@ -1080,7 +1064,12 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id * return err; } + sunserial_console_match(SUNSAB_CONSOLE(), op->node, + &sunsab_reg, up[0].port.line); uart_add_one_port(&sunsab_reg, &up[0].port); + + sunserial_console_match(SUNSAB_CONSOLE(), op->node, + &sunsab_reg, up[1].port.line); uart_add_one_port(&sunsab_reg, &up[1].port); dev_set_drvdata(&op->dev, &up[0]); @@ -1164,7 +1153,6 @@ static int __init sunsab_init(void) } sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64; - sunsab_reg.cons = SUNSAB_CONSOLE(); sunserial_current_minor += num_channels; } diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 26d720baf88..79b13685bdf 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1371,28 +1371,12 @@ static struct console sunsu_console = { * Register console. */ -static inline struct console *SUNSU_CONSOLE(int num_uart) +static inline struct console *SUNSU_CONSOLE(void) { - int i; - - if (con_is_present()) - return NULL; - - for (i = 0; i < num_uart; i++) { - int this_minor = sunsu_reg.minor + i; - - if ((this_minor - 64) == (serial_console - 1)) - break; - } - if (i == num_uart) - return NULL; - - sunsu_console.index = i; - return &sunsu_console; } #else -#define SUNSU_CONSOLE(num_uart) (NULL) +#define SUNSU_CONSOLE() (NULL) #define sunsu_serial_console_init() do { } while (0) #endif @@ -1482,6 +1466,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m up->port.ops = &sunsu_pops; + sunserial_console_match(SUNSU_CONSOLE(), dp, + &sunsu_reg, up->port.line); err = uart_add_one_port(&sunsu_reg, &up->port); if (err) goto out_unmap; @@ -1572,7 +1558,6 @@ static int __init sunsu_init(void) return err; sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; sunserial_current_minor += num_uart; - sunsu_reg.cons = SUNSU_CONSOLE(num_uart); } err = of_register_driver(&su_driver, &of_bus_type); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 0a3e10a4a35..1d262c0c613 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1226,23 +1226,6 @@ static struct console sunzilog_console_ops = { static inline struct console *SUNZILOG_CONSOLE(void) { - int i; - - if (con_is_present()) - return NULL; - - for (i = 0; i < NUM_CHANNELS; i++) { - int this_minor = sunzilog_reg.minor + i; - - if ((this_minor - 64) == (serial_console - 1)) - break; - } - if (i == NUM_CHANNELS) - return NULL; - - sunzilog_console_ops.index = i; - sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; - return &sunzilog_console_ops; } @@ -1428,12 +1411,18 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m sunzilog_init_hw(&up[1]); if (!keyboard_mouse) { + if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node, + &sunzilog_reg, up[0].port.line)) + up->flags |= SUNZILOG_FLAG_IS_CONS; err = uart_add_one_port(&sunzilog_reg, &up[0].port); if (err) { of_iounmap(&op->resource[0], rp, sizeof(struct zilog_layout)); return err; } + if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node, + &sunzilog_reg, up[1].port.line)) + up->flags |= SUNZILOG_FLAG_IS_CONS; err = uart_add_one_port(&sunzilog_reg, &up[1].port); if (err) { uart_remove_one_port(&sunzilog_reg, &up[0].port); @@ -1531,7 +1520,6 @@ static int __init sunzilog_init(void) goto out_free_tables; sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; - sunzilog_reg.cons = SUNZILOG_CONSOLE(); sunserial_current_minor += uart_count; } diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 0c7bf75732e..13990697b5c 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, int node, len, i, j, ret; u32 mem, chip_id; - /* Do not attach when we have a serial console. */ - if (!con_is_present()) - return -ENXIO; - /* * Map memory-mapped registers. */ diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index eb1a4812ad1..b87ea21d3d7 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -379,10 +379,6 @@ int __init igafb_init(void) if (fb_get_options("igafb", NULL)) return -ENODEV; - /* Do not attach when we have a serial console. */ - if (!con_is_present()) - return -ENXIO; - pdev = pci_get_device(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682, 0); if (pdev == NULL) { diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h index 91691e52c05..17ba82ee220 100644 --- a/include/asm-sparc/oplib.h +++ b/include/asm-sparc/oplib.h @@ -158,32 +158,6 @@ extern void prom_putchar(char character); extern void prom_printf(char *fmt, ...); extern void prom_write(const char *buf, unsigned int len); -/* Query for input device type */ - -enum prom_input_device { - PROMDEV_IKBD, /* input from keyboard */ - PROMDEV_ITTYA, /* input from ttya */ - PROMDEV_ITTYB, /* input from ttyb */ - PROMDEV_IRSC, /* input from rsc */ - PROMDEV_IVCONS, /* input from virtual-console */ - PROMDEV_I_UNK, -}; - -extern enum prom_input_device prom_query_input_device(void); - -/* Query for output device type */ - -enum prom_output_device { - PROMDEV_OSCREEN, /* to screen */ - PROMDEV_OTTYA, /* to ttya */ - PROMDEV_OTTYB, /* to ttyb */ - PROMDEV_ORSC, /* to rsc */ - PROMDEV_OVCONS, /* to virtual-console */ - PROMDEV_O_UNK, -}; - -extern enum prom_output_device prom_query_output_device(void); - /* Multiprocessor operations... */ /* Start the CPU with the given device tree node, context table, and context diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index db9feb75bd8..350676c589f 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -85,5 +85,9 @@ static inline void of_node_put(struct device_node *node) */ #include +extern struct device_node *of_console_device; +extern char *of_console_path; +extern char *of_console_options; + #endif /* __KERNEL__ */ #endif /* _SPARC_PROM_H */ diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h index 992f9f7a476..3f23c5dc5f2 100644 --- a/include/asm-sparc64/oplib.h +++ b/include/asm-sparc64/oplib.h @@ -140,32 +140,6 @@ extern void prom_putchar(char character); extern void prom_printf(const char *fmt, ...); extern void prom_write(const char *buf, unsigned int len); -/* Query for input device type */ - -enum prom_input_device { - PROMDEV_IKBD, /* input from keyboard */ - PROMDEV_ITTYA, /* input from ttya */ - PROMDEV_ITTYB, /* input from ttyb */ - PROMDEV_IRSC, /* input from rsc */ - PROMDEV_IVCONS, /* input from virtual-console */ - PROMDEV_I_UNK, -}; - -extern enum prom_input_device prom_query_input_device(void); - -/* Query for output device type */ - -enum prom_output_device { - PROMDEV_OSCREEN, /* to screen */ - PROMDEV_OTTYA, /* to ttya */ - PROMDEV_OTTYB, /* to ttyb */ - PROMDEV_ORSC, /* to rsc */ - PROMDEV_OVCONS, /* to virtual-console */ - PROMDEV_O_UNK, -}; - -extern enum prom_output_device prom_query_output_device(void); - /* Multiprocessor operations... */ #ifdef CONFIG_SMP /* Start the CPU with the given device tree node at the passed program @@ -319,6 +293,8 @@ extern int prom_inst2pkg(int); extern int prom_service_exists(const char *service_name); extern void prom_sun4v_guest_soft_state(void); +extern int prom_ihandle2path(int handle, char *buffer, int bufsize); + /* Client interface level routines. */ extern void prom_set_trap_table(unsigned long tba); extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa); diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 2b9e0d795fa..31dcb92fbae 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -94,5 +94,9 @@ static inline void of_node_put(struct device_node *node) */ #include +extern struct device_node *of_console_device; +extern char *of_console_path; +extern char *of_console_options; + #endif /* __KERNEL__ */ #endif /* _SPARC64_PROM_H */ diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index 409067408ee..64891cb10f0 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -115,14 +115,8 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ #ifndef __ASSEMBLY__ extern void sun_do_break(void); -extern int serial_console; extern int stop_a_enabled; -static __inline__ int con_is_present(void) -{ - return serial_console ? 0 : 1; -} - extern void synchronize_user_stack(void); extern void __flushw_user(void); -- cgit v1.2.3 From e865f3e6f4ef2d2617f5003c7c819ed15b5a511b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Jul 2007 20:59:54 -0700 Subject: [SPARC]: Define minimal struct dev_archdata, similarly to sparc64. Signed-off-by: David S. Miller --- include/asm-sparc/device.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/asm-sparc/device.h b/include/asm-sparc/device.h index d8f9872b0e2..4a56d84d69c 100644 --- a/include/asm-sparc/device.h +++ b/include/asm-sparc/device.h @@ -3,5 +3,17 @@ * * This file is released under the GPLv2 */ -#include +#ifndef _ASM_SPARC_DEVICE_H +#define _ASM_SPARC_DEVICE_H + +struct device_node; +struct of_device; + +struct dev_archdata { + struct device_node *prom_node; + struct of_device *op; +}; + +#endif /* _ASM_SPARC_DEVICE_H */ + -- cgit v1.2.3 From 3d6e470236bc759f43c9f2377899b526a50e2e63 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Jul 2007 22:03:25 -0700 Subject: [SPARC]: Make sure dev_archdata is filled in for all devices. Signed-off-by: David S. Miller --- arch/sparc/kernel/ebus.c | 5 +++++ arch/sparc/kernel/of_device.c | 5 +++++ arch/sparc64/kernel/ebus.c | 5 +++++ arch/sparc64/kernel/isa.c | 5 +++++ arch/sparc64/kernel/of_device.c | 5 +++++ drivers/sbus/sbus.c | 5 +++++ 6 files changed, 30 insertions(+) diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c index 7bb86b9cdaa..ac352eb6dff 100644 --- a/arch/sparc/kernel/ebus.c +++ b/arch/sparc/kernel/ebus.c @@ -148,6 +148,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d { const struct linux_prom_registers *regs; struct linux_ebus_child *child; + struct dev_archdata *sd; const int *irqs; int i, n, len; unsigned long baseaddr; @@ -234,6 +235,10 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d } } + sd = &dev->ofdev.dev.archdata; + sd->prom_node = dp; + sd->op = &dev->ofdev; + dev->ofdev.node = dp; dev->ofdev.dev.parent = &dev->bus->ofdev.dev; dev->ofdev.dev.bus = &ebus_bus_type; diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index 7176040caba..36383f73d68 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c @@ -420,11 +420,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp, { struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); const struct linux_prom_irqs *intr; + struct dev_archdata *sd; int len, i; if (!op) return NULL; + sd = &op->dev.archdata; + sd->prom_node = dp; + sd->op = op; + op->node = dp; op->clock_freq = of_getintprop_default(dp, "clock-frequency", diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index ad55a9bb50d..6d2956179cd 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -362,6 +362,7 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev) static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) { struct linux_ebus_child *child; + struct dev_archdata *sd; struct of_device *op; int i, len; @@ -387,6 +388,10 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de dev->irqs[i] = op->irqs[i]; } + sd = &dev->ofdev.dev.archdata; + sd->prom_node = dp; + sd->op = &dev->ofdev; + dev->ofdev.node = dp; dev->ofdev.dev.parent = &dev->bus->ofdev.dev; dev->ofdev.dev.bus = &ebus_bus_type; diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index 6a6882e57ff..1a1043fcf97 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -79,6 +79,7 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) while (dp) { struct sparc_isa_device *isa_dev; + struct dev_archdata *sd; isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL); if (!isa_dev) { @@ -86,6 +87,10 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) return; } + sd = &isa_dev->ofdev.dev.archdata; + sd->prom_node = dp; + sd->op = &isa_dev->ofdev; + isa_dev->ofdev.node = dp; isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev; isa_dev->ofdev.dev.bus = &isa_bus_type; diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 7b0dce9604e..4cc77485f53 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -752,11 +752,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp, { struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); const unsigned int *irq; + struct dev_archdata *sd; int len, i; if (!op) return NULL; + sd = &op->dev.archdata; + sd->prom_node = dp; + sd->op = op; + op->node = dp; op->clock_freq = of_getintprop_default(dp, "clock-frequency", diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 002643392d4..2553629ec15 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -33,6 +33,7 @@ struct sbus_bus *sbus_root; static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) { + struct dev_archdata *sd; unsigned long base; const void *pval; int len, err; @@ -67,6 +68,10 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde sbus_fill_device_irq(sdev); + sd = &sdev->ofdev.dev.archdata; + sd->prom_node = dp; + sd->op = &sdev->ofdev; + sdev->ofdev.node = dp; if (sdev->parent) sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev; -- cgit v1.2.3 From 58fb666643acee28d347de0b59bb938844c22f83 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 Jul 2007 22:51:07 -0700 Subject: [SPARC64]: Improve VIO device naming further. The best scheme to get uniqueness seems to be: FOO -- If node lacks "id" property FOO-$(ID) -- If node has "id" but parent lacks "cfg-handle" FOO-$(ID)-$(CFG_HANDLE) -- If node has both Signed-off-by: David S. Miller --- arch/sparc64/kernel/vio.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c index 491223a6628..3685daf5157 100644 --- a/arch/sparc64/kernel/vio.c +++ b/arch/sparc64/kernel/vio.c @@ -205,7 +205,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, struct device_node *dp; struct vio_dev *vdev; int err, tlen, clen; - const u64 *id; + const u64 *id, *cfg_handle; + u64 a; type = mdesc_get_property(hp, mp, "device-type", &tlen); if (!type) { @@ -221,26 +222,18 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, return NULL; } - if (!strcmp(type, "vdc-port")) { - u64 a; + id = mdesc_get_property(hp, mp, "id", NULL); - id = NULL; - mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) { - u64 target; + cfg_handle = NULL; + mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) { + u64 target; - target = mdesc_arc_target(hp, a); - id = mdesc_get_property(hp, target, + target = mdesc_arc_target(hp, a); + cfg_handle = mdesc_get_property(hp, target, "cfg-handle", NULL); - if (id) - break; - } - if (!id) { - printk(KERN_ERR "VIO: vdc-port lacks parent " - "cfg-handle.\n"); - return NULL; - } - } else - id = mdesc_get_property(hp, mp, "id", NULL); + if (cfg_handle) + break; + } bus_id_name = type; if (!strcmp(type, "domain-services-port")) @@ -285,10 +278,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s", bus_id_name); vdev->dev_no = ~(u64)0; - } else { + } else if (!cfg_handle) { snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu", bus_id_name, *id); vdev->dev_no = *id; + } else { + snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu-%lu", + bus_id_name, *cfg_handle, *id); + vdev->dev_no = *cfg_handle; } vdev->dev.parent = parent; -- cgit v1.2.3 From 5fc986100cb253897b4e16992e805343d30a819e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 Jul 2007 23:25:35 -0700 Subject: [SPARC64]: Handle multiple domain-services-port nodes properly. Signed-off-by: David S. Miller --- arch/sparc64/kernel/ds.c | 251 +++++++++++++++++++++++++++++------------------ 1 file changed, 157 insertions(+), 94 deletions(-) diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c index 1a2062ecb0b..8c5692e9f91 100644 --- a/arch/sparc64/kernel/ds.c +++ b/arch/sparc64/kernel/ds.c @@ -124,10 +124,11 @@ struct ds_data_nack { __u64 result; }; +struct ds_info; struct ds_cap_state { __u64 handle; - void (*data)(struct ldc_channel *lp, + void (*data)(struct ds_info *dp, struct ds_cap_state *cp, void *buf, int len); @@ -139,27 +140,27 @@ struct ds_cap_state { #define CAP_STATE_REGISTERED 0x02 }; -static void md_update_data(struct ldc_channel *lp, struct ds_cap_state *cp, +static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp, void *buf, int len); -static void domain_shutdown_data(struct ldc_channel *lp, +static void domain_shutdown_data(struct ds_info *dp, struct ds_cap_state *cp, void *buf, int len); -static void domain_panic_data(struct ldc_channel *lp, +static void domain_panic_data(struct ds_info *dp, struct ds_cap_state *cp, void *buf, int len); #ifdef CONFIG_HOTPLUG_CPU -static void dr_cpu_data(struct ldc_channel *lp, +static void dr_cpu_data(struct ds_info *dp, struct ds_cap_state *cp, void *buf, int len); #endif -static void ds_pri_data(struct ldc_channel *lp, +static void ds_pri_data(struct ds_info *dp, struct ds_cap_state *cp, void *buf, int len); -static void ds_var_data(struct ldc_channel *lp, +static void ds_var_data(struct ds_info *dp, struct ds_cap_state *cp, void *buf, int len); -struct ds_cap_state ds_states[] = { +struct ds_cap_state ds_states_template[] = { { .service_id = "md-update", .data = md_update_data, @@ -200,30 +201,38 @@ struct ds_info { #define DS_HS_START 0x01 #define DS_HS_DONE 0x02 + u64 id; + void *rcv_buf; int rcv_buf_len; + + struct ds_cap_state *ds_states; + int num_ds_states; + + struct ds_info *next; }; -static struct ds_info *ds_info; +static struct ds_info *ds_info_list; -static struct ds_cap_state *find_cap(u64 handle) +static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle) { unsigned int index = handle >> 32; - if (index >= ARRAY_SIZE(ds_states)) + if (index >= dp->num_ds_states) return NULL; - return &ds_states[index]; + return &dp->ds_states[index]; } -static struct ds_cap_state *find_cap_by_string(const char *name) +static struct ds_cap_state *find_cap_by_string(struct ds_info *dp, + const char *name) { int i; - for (i = 0; i < ARRAY_SIZE(ds_states); i++) { - if (strcmp(ds_states[i].service_id, name)) + for (i = 0; i < dp->num_ds_states; i++) { + if (strcmp(dp->ds_states[i].service_id, name)) continue; - return &ds_states[i]; + return &dp->ds_states[i]; } return NULL; } @@ -264,10 +273,11 @@ struct ds_md_update_res { __u32 result; }; -static void md_update_data(struct ldc_channel *lp, - struct ds_cap_state *dp, +static void md_update_data(struct ds_info *dp, + struct ds_cap_state *cp, void *buf, int len) { + struct ldc_channel *lp = dp->lp; struct ds_data *dpkt = buf; struct ds_md_update_req *rp; struct { @@ -277,14 +287,14 @@ static void md_update_data(struct ldc_channel *lp, rp = (struct ds_md_update_req *) (dpkt + 1); - printk(KERN_INFO PFX "Machine description update.\n"); + printk(KERN_INFO "ds-%lu: Machine description update.\n", dp->id); mdesc_update(); memset(&pkt, 0, sizeof(pkt)); pkt.data.tag.type = DS_DATA; pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag); - pkt.data.handle = dp->handle; + pkt.data.handle = cp->handle; pkt.res.req_num = rp->req_num; pkt.res.result = DS_OK; @@ -302,10 +312,11 @@ struct ds_shutdown_res { char reason[1]; }; -static void domain_shutdown_data(struct ldc_channel *lp, - struct ds_cap_state *dp, +static void domain_shutdown_data(struct ds_info *dp, + struct ds_cap_state *cp, void *buf, int len) { + struct ldc_channel *lp = dp->lp; struct ds_data *dpkt = buf; struct ds_shutdown_req *rp; struct { @@ -315,13 +326,13 @@ static void domain_shutdown_data(struct ldc_channel *lp, rp = (struct ds_shutdown_req *) (dpkt + 1); - printk(KERN_ALERT PFX "Shutdown request from " - "LDOM manager received.\n"); + printk(KERN_ALERT "ds-%lu: Shutdown request from " + "LDOM manager received.\n", dp->id); memset(&pkt, 0, sizeof(pkt)); pkt.data.tag.type = DS_DATA; pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag); - pkt.data.handle = dp->handle; + pkt.data.handle = cp->handle; pkt.res.req_num = rp->req_num; pkt.res.result = DS_OK; pkt.res.reason[0] = 0; @@ -341,10 +352,11 @@ struct ds_panic_res { char reason[1]; }; -static void domain_panic_data(struct ldc_channel *lp, - struct ds_cap_state *dp, +static void domain_panic_data(struct ds_info *dp, + struct ds_cap_state *cp, void *buf, int len) { + struct ldc_channel *lp = dp->lp; struct ds_data *dpkt = buf; struct ds_panic_req *rp; struct { @@ -354,13 +366,13 @@ static void domain_panic_data(struct ldc_channel *lp, rp = (struct ds_panic_req *) (dpkt + 1); - printk(KERN_ALERT PFX "Panic request from " - "LDOM manager received.\n"); + printk(KERN_ALERT "ds-%lu: Panic request from " + "LDOM manager received.\n", dp->id); memset(&pkt, 0, sizeof(pkt)); pkt.data.tag.type = DS_DATA; pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag); - pkt.data.handle = dp->handle; + pkt.data.handle = cp->handle; pkt.res.req_num = rp->req_num; pkt.res.result = DS_OK; pkt.res.reason[0] = 0; @@ -403,10 +415,11 @@ struct dr_cpu_resp_entry { __u32 str_off; }; -static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data) +static void __dr_cpu_send_error(struct ds_info *dp, + struct ds_cap_state *cp, + struct ds_data *data) { struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1); - struct ds_info *dp = ds_info; struct { struct ds_data data; struct dr_cpu_tag tag; @@ -428,12 +441,14 @@ static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data) __ds_send(dp->lp, &pkt, msg_len); } -static void dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data) +static void dr_cpu_send_error(struct ds_info *dp, + struct ds_cap_state *cp, + struct ds_data *data) { unsigned long flags; spin_lock_irqsave(&ds_lock, flags); - __dr_cpu_send_error(cp, data); + __dr_cpu_send_error(dp, cp, data); spin_unlock_irqrestore(&ds_lock, flags); } @@ -511,7 +526,9 @@ static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus, } } -static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num, +static int dr_cpu_configure(struct ds_info *dp, + struct ds_cap_state *cp, + u64 req_num, cpumask_t *mask) { struct ds_data *resp; @@ -533,7 +550,8 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num, for_each_cpu_mask(cpu, *mask) { int err; - printk(KERN_INFO PFX "Starting cpu %d...\n", cpu); + printk(KERN_INFO "ds-%lu: Starting cpu %d...\n", + dp->id, cpu); err = cpu_up(cpu); if (err) { __u32 res = DR_CPU_RES_FAILURE; @@ -548,14 +566,14 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num, res = DR_CPU_RES_CPU_NOT_RESPONDING; } - printk(KERN_INFO PFX "CPU startup failed err=%d\n", - err); + printk(KERN_INFO "ds-%lu: CPU startup failed err=%d\n", + dp->id, err); dr_cpu_mark(resp, cpu, ncpus, res, stat); } } spin_lock_irqsave(&ds_lock, flags); - __ds_send(ds_info->lp, resp, resp_len); + __ds_send(dp->lp, resp, resp_len); spin_unlock_irqrestore(&ds_lock, flags); kfree(resp); @@ -566,7 +584,9 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num, return 0; } -static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num, +static int dr_cpu_unconfigure(struct ds_info *dp, + struct ds_cap_state *cp, + u64 req_num, cpumask_t *mask) { struct ds_data *resp; @@ -586,8 +606,8 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num, for_each_cpu_mask(cpu, *mask) { int err; - printk(KERN_INFO PFX "CPU[%d]: Shutting down cpu %d...\n", - smp_processor_id(), cpu); + printk(KERN_INFO "ds-%lu: Shutting down cpu %d...\n", + dp->id, cpu); err = cpu_down(cpu); if (err) dr_cpu_mark(resp, cpu, ncpus, @@ -596,7 +616,7 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num, } spin_lock_irqsave(&ds_lock, flags); - __ds_send(ds_info->lp, resp, resp_len); + __ds_send(dp->lp, resp, resp_len); spin_unlock_irqrestore(&ds_lock, flags); kfree(resp); @@ -604,7 +624,7 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num, return 0; } -static void dr_cpu_data(struct ldc_channel *lp, +static void dr_cpu_data(struct ds_info *dp, struct ds_cap_state *cp, void *buf, int len) { @@ -623,7 +643,7 @@ static void dr_cpu_data(struct ldc_channel *lp, break; default: - dr_cpu_send_error(cp, data); + dr_cpu_send_error(dp, cp, data); return; } @@ -639,12 +659,12 @@ static void dr_cpu_data(struct ldc_channel *lp, } if (tag->type == DR_CPU_CONFIGURE) - err = dr_cpu_configure(cp, req_num, &mask); + err = dr_cpu_configure(dp, cp, req_num, &mask); else - err = dr_cpu_unconfigure(cp, req_num, &mask); + err = dr_cpu_unconfigure(dp, cp, req_num, &mask); if (err) - dr_cpu_send_error(cp, data); + dr_cpu_send_error(dp, cp, data); } #endif /* CONFIG_HOTPLUG_CPU */ @@ -656,8 +676,8 @@ struct ds_pri_msg { #define DS_PRI_UPDATE 0x02 }; -static void ds_pri_data(struct ldc_channel *lp, - struct ds_cap_state *dp, +static void ds_pri_data(struct ds_info *dp, + struct ds_cap_state *cp, void *buf, int len) { struct ds_data *dpkt = buf; @@ -665,8 +685,8 @@ static void ds_pri_data(struct ldc_channel *lp, rp = (struct ds_pri_msg *) (dpkt + 1); - printk(KERN_INFO PFX "PRI REQ [%lx:%lx], len=%d\n", - rp->req_num, rp->type, len); + printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n", + dp->id, rp->req_num, rp->type, len); } struct ds_var_hdr { @@ -701,8 +721,8 @@ static DEFINE_MUTEX(ds_var_mutex); static int ds_var_doorbell; static int ds_var_response; -static void ds_var_data(struct ldc_channel *lp, - struct ds_cap_state *dp, +static void ds_var_data(struct ds_info *dp, + struct ds_cap_state *cp, void *buf, int len) { struct ds_data *dpkt = buf; @@ -721,14 +741,35 @@ static void ds_var_data(struct ldc_channel *lp, void ldom_set_var(const char *var, const char *value) { - struct ds_info *dp = ds_info; struct ds_cap_state *cp; + struct ds_info *dp; + unsigned long flags; + + spin_lock_irqsave(&ds_lock, flags); + cp = NULL; + for (dp = ds_info_list; dp; dp = dp->next) { + struct ds_cap_state *tmp; + + tmp = find_cap_by_string(dp, "var-config"); + if (tmp && tmp->state == CAP_STATE_REGISTERED) { + cp = tmp; + break; + } + } + if (!cp) { + for (dp = ds_info_list; dp; dp = dp->next) { + struct ds_cap_state *tmp; - cp = find_cap_by_string("var-config"); - if (cp->state != CAP_STATE_REGISTERED) - cp = find_cap_by_string("var-config-backup"); + tmp = find_cap_by_string(dp, "var-config-backup"); + if (tmp && tmp->state == CAP_STATE_REGISTERED) { + cp = tmp; + break; + } + } + } + spin_unlock_irqrestore(&ds_lock, flags); - if (cp->state == CAP_STATE_REGISTERED) { + if (cp) { union { struct { struct ds_data data; @@ -736,7 +777,6 @@ void ldom_set_var(const char *var, const char *value) } header; char all[512]; } pkt; - unsigned long flags; char *base, *p; int msg_len, loops; @@ -777,9 +817,9 @@ void ldom_set_var(const char *var, const char *value) if (ds_var_doorbell == 0 || ds_var_response != DS_VAR_SUCCESS) - printk(KERN_ERR PFX "var-config [%s:%s] " + printk(KERN_ERR "ds-%lu: var-config [%s:%s] " "failed, response(%d).\n", - var, value, + dp->id, var, value, ds_var_response); } else { printk(KERN_ERR PFX "var-config not registered so " @@ -811,8 +851,8 @@ void ldom_power_off(void) static void ds_conn_reset(struct ds_info *dp) { - printk(KERN_ERR PFX "ds_conn_reset() from %p\n", - __builtin_return_address(0)); + printk(KERN_ERR "ds-%lu: ds_conn_reset() from %p\n", + dp->id, __builtin_return_address(0)); } static int register_services(struct ds_info *dp) @@ -820,12 +860,12 @@ static int register_services(struct ds_info *dp) struct ldc_channel *lp = dp->lp; int i; - for (i = 0; i < ARRAY_SIZE(ds_states); i++) { + for (i = 0; i < dp->num_ds_states; i++) { struct { struct ds_reg_req req; u8 id_buf[256]; } pbuf; - struct ds_cap_state *cp = &ds_states[i]; + struct ds_cap_state *cp = &dp->ds_states[i]; int err, msg_len; u64 new_count; @@ -870,28 +910,28 @@ static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt) if (pkt->type == DS_REG_ACK) { struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt; - struct ds_cap_state *cp = find_cap(ap->handle); + struct ds_cap_state *cp = find_cap(dp, ap->handle); if (!cp) { - printk(KERN_ERR PFX "REG ACK for unknown handle %lx\n", - ap->handle); + printk(KERN_ERR "ds-%lu: REG ACK for unknown " + "handle %lx\n", dp->id, ap->handle); return 0; } - printk(KERN_INFO PFX "Registered %s service.\n", - cp->service_id); + printk(KERN_INFO "ds-%lu: Registered %s service.\n", + dp->id, cp->service_id); cp->state = CAP_STATE_REGISTERED; } else if (pkt->type == DS_REG_NACK) { struct ds_reg_nack *np = (struct ds_reg_nack *) pkt; - struct ds_cap_state *cp = find_cap(np->handle); + struct ds_cap_state *cp = find_cap(dp, np->handle); if (!cp) { - printk(KERN_ERR PFX "REG NACK for " + printk(KERN_ERR "ds-%lu: REG NACK for " "unknown handle %lx\n", - np->handle); + dp->id, np->handle); return 0; } - printk(KERN_INFO PFX "Could not register %s service\n", - cp->service_id); + printk(KERN_INFO "ds-%lu: Could not register %s service\n", + dp->id, cp->service_id); cp->state = CAP_STATE_UNKNOWN; } @@ -922,6 +962,7 @@ static DECLARE_WAIT_QUEUE_HEAD(ds_wait); struct ds_queue_entry { struct list_head list; + struct ds_info *dp; int req_len; int __pad; u64 req[0]; @@ -930,7 +971,6 @@ struct ds_queue_entry { static void process_ds_work(void) { struct ds_queue_entry *qp, *tmp; - static struct ds_info *dp; unsigned long flags; LIST_HEAD(todo); @@ -939,22 +979,22 @@ static void process_ds_work(void) INIT_LIST_HEAD(&ds_work_list); spin_unlock_irqrestore(&ds_lock, flags); - dp = ds_info; - list_for_each_entry_safe(qp, tmp, &todo, list) { struct ds_data *dpkt = (struct ds_data *) qp->req; - struct ds_cap_state *cp = find_cap(dpkt->handle); + struct ds_info *dp = qp->dp; + struct ds_cap_state *cp = find_cap(dp, dpkt->handle); int req_len = qp->req_len; if (!cp) { - printk(KERN_ERR PFX "Data for unknown handle %lu\n", - dpkt->handle); + printk(KERN_ERR "ds-%lu: Data for unknown " + "handle %lu\n", + dp->id, dpkt->handle); spin_lock_irqsave(&ds_lock, flags); __send_ds_nack(dp, dpkt->handle); spin_unlock_irqrestore(&ds_lock, flags); } else { - cp->data(dp->lp, cp, dpkt, req_len); + cp->data(dp, cp, dpkt, req_len); } list_del(&qp->list); @@ -990,6 +1030,7 @@ static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len) if (!qp) { __send_ds_nack(dp, dpkt->handle); } else { + qp->dp = dp; memcpy(&qp->req, pkt, len); list_add_tail(&qp->list, &ds_work_list); wake_up(&ds_wait); @@ -1019,8 +1060,8 @@ static void ds_reset(struct ds_info *dp) dp->hs_state = 0; - for (i = 0; i < ARRAY_SIZE(ds_states); i++) { - struct ds_cap_state *cp = &ds_states[i]; + for (i = 0; i < dp->num_ds_states; i++) { + struct ds_cap_state *cp = &dp->ds_states[i]; cp->state = CAP_STATE_UNKNOWN; } @@ -1048,7 +1089,8 @@ static void ds_event(void *arg, int event) } if (event != LDC_EVENT_DATA_READY) { - printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event); + printk(KERN_WARNING "ds-%lu: Unexpected LDC event %d\n", + dp->id, event); spin_unlock_irqrestore(&ds_lock, flags); return; } @@ -1099,9 +1141,11 @@ static int __devinit ds_probe(struct vio_dev *vdev, .mtu = 4096, .mode = LDC_MODE_STREAM, }; + struct mdesc_handle *hp; struct ldc_channel *lp; struct ds_info *dp; - int err; + const u64 *val; + int err, i; if (ds_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -1111,19 +1155,37 @@ static int __devinit ds_probe(struct vio_dev *vdev, if (!dp) goto out_err; + hp = mdesc_grab(); + val = mdesc_get_property(hp, vdev->mp, "id", NULL); + if (val) + dp->id = *val; + mdesc_release(hp); + dp->rcv_buf = kzalloc(4096, GFP_KERNEL); if (!dp->rcv_buf) goto out_free_dp; dp->rcv_buf_len = 4096; + dp->ds_states = kzalloc(sizeof(ds_states_template), + GFP_KERNEL); + if (!dp->ds_states) + goto out_free_rcv_buf; + + memcpy(dp->ds_states, ds_states_template, + sizeof(ds_states_template)); + dp->num_ds_states = ARRAY_SIZE(ds_states_template); + + for (i = 0; i < dp->num_ds_states; i++) + dp->ds_states[i].handle = ((u64)i << 32); + ds_cfg.tx_irq = vdev->tx_irq; ds_cfg.rx_irq = vdev->rx_irq; lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp); if (IS_ERR(lp)) { err = PTR_ERR(lp); - goto out_free_rcv_buf; + goto out_free_ds_states; } dp->lp = lp; @@ -1131,13 +1193,19 @@ static int __devinit ds_probe(struct vio_dev *vdev, if (err) goto out_free_ldc; - ds_info = dp; + spin_lock_irq(&ds_lock); + dp->next = ds_info_list; + ds_info_list = dp; + spin_unlock_irq(&ds_lock); return err; out_free_ldc: ldc_free(dp->lp); +out_free_ds_states: + kfree(dp->ds_states); + out_free_rcv_buf: kfree(dp->rcv_buf); @@ -1172,11 +1240,6 @@ static struct vio_driver ds_driver = { static int __init ds_init(void) { - int i; - - for (i = 0; i < ARRAY_SIZE(ds_states); i++) - ds_states[i].handle = ((u64)i << 32); - kthread_run(ds_thread, NULL, "kldomd"); return vio_register_driver(&ds_driver); -- cgit v1.2.3 From 028ebff26915df18ab0cda664e2f0582650af155 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 20 Jul 2007 02:30:25 -0700 Subject: [SPARC64]: Add proper multicast support to VNET driver. Signed-off-by: David S. Miller --- drivers/net/sunvnet.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++- drivers/net/sunvnet.h | 11 ++++ 2 files changed, 146 insertions(+), 2 deletions(-) diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index ef0066bab2c..61f98251fea 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -459,6 +459,22 @@ static int vnet_nack(struct vnet_port *port, void *msgbuf) return 0; } +static int handle_mcast(struct vnet_port *port, void *msgbuf) +{ + struct vio_net_mcast_info *pkt = msgbuf; + + if (pkt->tag.stype != VIO_SUBTYPE_ACK) + printk(KERN_ERR PFX "%s: Got unexpected MCAST reply " + "[%02x:%02x:%04x:%08x]\n", + port->vp->dev->name, + pkt->tag.type, + pkt->tag.stype, + pkt->tag.stype_env, + pkt->tag.sid); + + return 0; +} + static void maybe_tx_wakeup(struct vnet *vp) { struct net_device *dev = vp->dev; @@ -544,7 +560,10 @@ static void vnet_event(void *arg, int event) err = vnet_nack(port, &msgbuf); } } else if (msgbuf.tag.type == VIO_TYPE_CTRL) { - err = vio_control_pkt_engine(vio, &msgbuf); + if (msgbuf.tag.stype_env == VNET_MCAST_INFO) + err = handle_mcast(port, &msgbuf); + else + err = vio_control_pkt_engine(vio, &msgbuf); if (err) break; } else { @@ -731,9 +750,122 @@ static int vnet_close(struct net_device *dev) return 0; } +static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr) +{ + struct vnet_mcast_entry *m; + + for (m = vp->mcast_list; m; m = m->next) { + if (!memcmp(m->addr, addr, ETH_ALEN)) + return m; + } + return NULL; +} + +static void __update_mc_list(struct vnet *vp, struct net_device *dev) +{ + struct dev_addr_list *p; + + for (p = dev->mc_list; p; p = p->next) { + struct vnet_mcast_entry *m; + + m = __vnet_mc_find(vp, p->dmi_addr); + if (m) { + m->hit = 1; + continue; + } + + if (!m) { + m = kzalloc(sizeof(*m), GFP_ATOMIC); + if (!m) + continue; + memcpy(m->addr, p->dmi_addr, ETH_ALEN); + m->hit = 1; + + m->next = vp->mcast_list; + vp->mcast_list = m; + } + } +} + +static void __send_mc_list(struct vnet *vp, struct vnet_port *port) +{ + struct vio_net_mcast_info info; + struct vnet_mcast_entry *m, **pp; + int n_addrs; + + memset(&info, 0, sizeof(info)); + + info.tag.type = VIO_TYPE_CTRL; + info.tag.stype = VIO_SUBTYPE_INFO; + info.tag.stype_env = VNET_MCAST_INFO; + info.tag.sid = vio_send_sid(&port->vio); + info.set = 1; + + n_addrs = 0; + for (m = vp->mcast_list; m; m = m->next) { + if (m->sent) + continue; + m->sent = 1; + memcpy(&info.mcast_addr[n_addrs * ETH_ALEN], + m->addr, ETH_ALEN); + if (++n_addrs == VNET_NUM_MCAST) { + info.count = n_addrs; + + (void) vio_ldc_send(&port->vio, &info, + sizeof(info)); + n_addrs = 0; + } + } + if (n_addrs) { + info.count = n_addrs; + (void) vio_ldc_send(&port->vio, &info, sizeof(info)); + } + + info.set = 0; + + n_addrs = 0; + pp = &vp->mcast_list; + while ((m = *pp) != NULL) { + if (m->hit) { + m->hit = 0; + pp = &m->next; + continue; + } + + memcpy(&info.mcast_addr[n_addrs * ETH_ALEN], + m->addr, ETH_ALEN); + if (++n_addrs == VNET_NUM_MCAST) { + info.count = n_addrs; + (void) vio_ldc_send(&port->vio, &info, + sizeof(info)); + n_addrs = 0; + } + + *pp = m->next; + kfree(m); + } + if (n_addrs) { + info.count = n_addrs; + (void) vio_ldc_send(&port->vio, &info, sizeof(info)); + } +} + static void vnet_set_rx_mode(struct net_device *dev) { - /* XXX Implement multicast support XXX */ + struct vnet *vp = netdev_priv(dev); + struct vnet_port *port; + unsigned long flags; + + spin_lock_irqsave(&vp->lock, flags); + if (!list_empty(&vp->port_list)) { + port = list_entry(vp->port_list.next, struct vnet_port, list); + + if (port->switch_port) { + __update_mc_list(vp, dev); + __send_mc_list(vp, port); + } + } + spin_unlock_irqrestore(&vp->lock, flags); } static int vnet_change_mtu(struct net_device *dev, int new_mtu) @@ -1070,6 +1202,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, switch_port = 0; if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL) switch_port = 1; + port->switch_port = switch_port; spin_lock_irqsave(&vp->lock, flags); if (switch_port) diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h index 7d3a0cac727..d347a5bf24b 100644 --- a/drivers/net/sunvnet.h +++ b/drivers/net/sunvnet.h @@ -30,6 +30,8 @@ struct vnet_port { struct hlist_node hash; u8 raddr[ETH_ALEN]; + u8 switch_port; + u8 __pad; struct vnet *vp; @@ -53,6 +55,13 @@ static inline unsigned int vnet_hashfn(u8 *mac) return val & (VNET_PORT_HASH_MASK); } +struct vnet_mcast_entry { + u8 addr[ETH_ALEN]; + u8 sent; + u8 hit; + struct vnet_mcast_entry *next; +}; + struct vnet { /* Protects port_list and port_hash. */ spinlock_t lock; @@ -65,6 +74,8 @@ struct vnet { struct hlist_head port_hash[VNET_PORT_HASH_SIZE]; + struct vnet_mcast_entry *mcast_list; + struct list_head list; u64 local_mac; }; -- cgit v1.2.3 From afd69ed142a3aa8df81ea54e5e78d77dbcf08467 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 20 Jul 2007 02:34:41 -0700 Subject: [SPARC64]: Do not flood log with failed DS messages. When booting up a control node it's quite common to not be able to register several service types. And likewise on guests at least one or two are going to not be there. Signed-off-by: David S. Miller --- arch/sparc64/kernel/ds.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c index 8c5692e9f91..9f472a79d37 100644 --- a/arch/sparc64/kernel/ds.c +++ b/arch/sparc64/kernel/ds.c @@ -930,8 +930,6 @@ static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt) dp->id, np->handle); return 0; } - printk(KERN_INFO "ds-%lu: Could not register %s service\n", - dp->id, cp->service_id); cp->state = CAP_STATE_UNKNOWN; } -- cgit v1.2.3 From e83fb17f9ba6ea0c64d084cca0c557d7e7dc9693 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 20 Jul 2007 02:39:04 -0700 Subject: [SPARC64]: Use KERN_ERR in IRQ manipulation error printks. Signed-off-by: David S. Miller --- arch/sparc64/kernel/irq.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index c72795666a6..edd530fb4e3 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -336,15 +336,15 @@ static void sun4v_irq_enable(unsigned int virt_irq) err = sun4v_intr_settarget(ino, cpuid); if (err != HV_EOK) - printk("sun4v_intr_settarget(%x,%lu): err(%d)\n", - ino, cpuid, err); + printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): " + "err(%d)\n", ino, cpuid, err); err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE); if (err != HV_EOK) - printk("sun4v_intr_setstate(%x): " + printk(KERN_ERR "sun4v_intr_setstate(%x): " "err(%d)\n", ino, err); err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED); if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): err(%d)\n", + printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n", ino, err); } } @@ -362,8 +362,8 @@ static void sun4v_set_affinity(unsigned int virt_irq, cpumask_t mask) err = sun4v_intr_settarget(ino, cpuid); if (err != HV_EOK) - printk("sun4v_intr_settarget(%x,%lu): err(%d)\n", - ino, cpuid, err); + printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): " + "err(%d)\n", ino, cpuid, err); } } @@ -377,7 +377,7 @@ static void sun4v_irq_disable(unsigned int virt_irq) err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): " + printk(KERN_ERR "sun4v_intr_setenabled(%x): " "err(%d)\n", ino, err); } } @@ -410,7 +410,7 @@ static void sun4v_irq_end(unsigned int virt_irq) err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE); if (err != HV_EOK) - printk("sun4v_intr_setstate(%x): " + printk(KERN_ERR "sun4v_intr_setstate(%x): " "err(%d)\n", ino, err); } } @@ -431,19 +431,19 @@ static void sun4v_virq_enable(unsigned int virt_irq) err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); if (err != HV_EOK) - printk("sun4v_vintr_set_target(%lx,%lx,%lu): " + printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): " "err(%d)\n", dev_handle, dev_ino, cpuid, err); err = sun4v_vintr_set_state(dev_handle, dev_ino, HV_INTR_STATE_IDLE); if (err != HV_EOK) - printk("sun4v_vintr_set_state(%lx,%lx," + printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx," "HV_INTR_STATE_IDLE): err(%d)\n", dev_handle, dev_ino, err); err = sun4v_vintr_set_valid(dev_handle, dev_ino, HV_INTR_ENABLED); if (err != HV_EOK) - printk("sun4v_vintr_set_state(%lx,%lx," + printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx," "HV_INTR_ENABLED): err(%d)\n", dev_handle, dev_ino, err); } @@ -465,7 +465,7 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask) err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); if (err != HV_EOK) - printk("sun4v_vintr_set_target(%lx,%lx,%lu): " + printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): " "err(%d)\n", dev_handle, dev_ino, cpuid, err); } @@ -486,7 +486,7 @@ static void sun4v_virq_disable(unsigned int virt_irq) err = sun4v_vintr_set_valid(dev_handle, dev_ino, HV_INTR_DISABLED); if (err != HV_EOK) - printk("sun4v_vintr_set_state(%lx,%lx," + printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx," "HV_INTR_DISABLED): err(%d)\n", dev_handle, dev_ino, err); } @@ -511,7 +511,7 @@ static void sun4v_virq_end(unsigned int virt_irq) err = sun4v_vintr_set_state(dev_handle, dev_ino, HV_INTR_STATE_IDLE); if (err != HV_EOK) - printk("sun4v_vintr_set_state(%lx,%lx," + printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx," "HV_INTR_STATE_IDLE): err(%d)\n", dev_handle, dev_ino, err); } -- cgit v1.2.3 From 93b3238ef8b04f1383b2aa7704487fb3c0e44193 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 20 Jul 2007 02:58:28 -0700 Subject: [SPARC64]: Fix virq decomposition. The dev_handle and dev_ino fields don't match up exactly to the traditional IMAP_IGN and IMAP_INO masks. So store them away in a table and look them up directly. Signed-off-by: David S. Miller --- arch/sparc64/kernel/irq.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index edd530fb4e3..db31bf6b42d 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -87,7 +87,11 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY */ #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) -static unsigned int virt_to_real_irq_table[NR_IRQS]; +static struct { + unsigned int irq; + unsigned int dev_handle; + unsigned int dev_ino; +} virt_to_real_irq_table[NR_IRQS]; static unsigned char virt_irq_alloc(unsigned int real_irq) { @@ -96,7 +100,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq) BUILD_BUG_ON(NR_IRQS >= 256); for (ent = 1; ent < NR_IRQS; ent++) { - if (!virt_to_real_irq_table[ent]) + if (!virt_to_real_irq_table[ent].irq) break; } if (ent >= NR_IRQS) { @@ -104,7 +108,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq) return 0; } - virt_to_real_irq_table[ent] = real_irq; + virt_to_real_irq_table[ent].irq = real_irq; return ent; } @@ -117,8 +121,8 @@ static void virt_irq_free(unsigned int virt_irq) if (virt_irq >= NR_IRQS) return; - real_irq = virt_to_real_irq_table[virt_irq]; - virt_to_real_irq_table[virt_irq] = 0; + real_irq = virt_to_real_irq_table[virt_irq].irq; + virt_to_real_irq_table[virt_irq].irq = 0; __bucket(real_irq)->virt_irq = 0; } @@ -126,7 +130,7 @@ static void virt_irq_free(unsigned int virt_irq) static unsigned int virt_to_real_irq(unsigned char virt_irq) { - return virt_to_real_irq_table[virt_irq]; + return virt_to_real_irq_table[virt_irq].irq; } /* @@ -418,7 +422,6 @@ static void sun4v_irq_end(unsigned int virt_irq) static void sun4v_virq_enable(unsigned int virt_irq) { struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); - unsigned int ino = bucket - &ivector_table[0]; if (likely(bucket)) { unsigned long cpuid, dev_handle, dev_ino; @@ -426,8 +429,8 @@ static void sun4v_virq_enable(unsigned int virt_irq) cpuid = irq_choose_cpu(virt_irq); - dev_handle = ino & IMAP_IGN; - dev_ino = ino & IMAP_INO; + dev_handle = virt_to_real_irq_table[virt_irq].dev_handle; + dev_ino = virt_to_real_irq_table[virt_irq].dev_ino; err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); if (err != HV_EOK) @@ -452,7 +455,6 @@ static void sun4v_virq_enable(unsigned int virt_irq) static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask) { struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); - unsigned int ino = bucket - &ivector_table[0]; if (likely(bucket)) { unsigned long cpuid, dev_handle, dev_ino; @@ -460,8 +462,8 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask) cpuid = irq_choose_cpu(virt_irq); - dev_handle = ino & IMAP_IGN; - dev_ino = ino & IMAP_INO; + dev_handle = virt_to_real_irq_table[virt_irq].dev_handle; + dev_ino = virt_to_real_irq_table[virt_irq].dev_ino; err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); if (err != HV_EOK) @@ -474,14 +476,13 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask) static void sun4v_virq_disable(unsigned int virt_irq) { struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); - unsigned int ino = bucket - &ivector_table[0]; if (likely(bucket)) { unsigned long dev_handle, dev_ino; int err; - dev_handle = ino & IMAP_IGN; - dev_ino = ino & IMAP_INO; + dev_handle = virt_to_real_irq_table[virt_irq].dev_handle; + dev_ino = virt_to_real_irq_table[virt_irq].dev_ino; err = sun4v_vintr_set_valid(dev_handle, dev_ino, HV_INTR_DISABLED); @@ -495,7 +496,6 @@ static void sun4v_virq_disable(unsigned int virt_irq) static void sun4v_virq_end(unsigned int virt_irq) { struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); - unsigned int ino = bucket - &ivector_table[0]; struct irq_desc *desc = irq_desc + virt_irq; if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))) @@ -505,8 +505,8 @@ static void sun4v_virq_end(unsigned int virt_irq) unsigned long dev_handle, dev_ino; int err; - dev_handle = ino & IMAP_IGN; - dev_ino = ino & IMAP_INO; + dev_handle = virt_to_real_irq_table[virt_irq].dev_handle; + dev_ino = virt_to_real_irq_table[virt_irq].dev_ino; err = sun4v_vintr_set_state(dev_handle, dev_ino, HV_INTR_STATE_IDLE); @@ -700,6 +700,7 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) { unsigned long sysino, hv_err; + unsigned int virq; BUG_ON(devhandle & devino); @@ -713,7 +714,12 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) prom_halt(); } - return sun4v_build_common(sysino, &sun4v_virq); + virq = sun4v_build_common(sysino, &sun4v_virq); + + virt_to_real_irq_table[virq].dev_handle = devhandle; + virt_to_real_irq_table[virq].dev_ino = devino; + + return virq; } #ifdef CONFIG_PCI_MSI -- cgit v1.2.3 From 3adf55ad5c0fcabf1c53bb274f39953cb1d6698f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Jul 2007 22:03:58 -0700 Subject: [SPARC]: Implement fb_is_primary_device(). Signed-off-by: David S. Miller --- include/asm-sparc/fb.h | 9 +++++++++ include/asm-sparc64/fb.h | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/include/asm-sparc/fb.h b/include/asm-sparc/fb.h index c7df3803099..c73ca081e1f 100644 --- a/include/asm-sparc/fb.h +++ b/include/asm-sparc/fb.h @@ -1,11 +1,20 @@ #ifndef _ASM_FB_H_ #define _ASM_FB_H_ #include +#include #define fb_pgprotect(...) do {} while (0) static inline int fb_is_primary_device(struct fb_info *info) { + struct device *dev = info->device; + struct device_node *node; + + node = dev->archdata.prom_node; + if (node && + node == of_console_device) + return 1; + return 0; } diff --git a/include/asm-sparc64/fb.h b/include/asm-sparc64/fb.h index d6cd3a175fc..389012e5fba 100644 --- a/include/asm-sparc64/fb.h +++ b/include/asm-sparc64/fb.h @@ -3,6 +3,7 @@ #include #include #include +#include static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, unsigned long off) @@ -12,6 +13,14 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, static inline int fb_is_primary_device(struct fb_info *info) { + struct device *dev = info->device; + struct device_node *node; + + node = dev->archdata.prom_node; + if (node && + node == of_console_device) + return 1; + return 0; } -- cgit v1.2.3 From 0fe85d504b47267bcdb25a563c535aa2ae075ff4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Jul 2007 23:15:04 -0700 Subject: [SPARC64]: Convert parport to of_platform_driver. Signed-off-by: David S. Miller --- include/asm-sparc64/parport.h | 233 ++++++++++++++++++++++++------------------ 1 file changed, 133 insertions(+), 100 deletions(-) diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h index 23cc63f049a..600afe5ae2e 100644 --- a/include/asm-sparc64/parport.h +++ b/include/asm-sparc64/parport.h @@ -8,8 +8,9 @@ #define _ASM_SPARC64_PARPORT_H 1 #include -#include #include +#include +#include #define PARPORT_PC_MAX_PORTS PARPORT_MAX @@ -35,8 +36,12 @@ static struct sparc_ebus_info { unsigned int addr; unsigned int count; int lock; + + struct parport *port; } sparc_ebus_dmas[PARPORT_PC_MAX_PORTS]; +static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS); + static __inline__ int request_dma(unsigned int dmanr, const char *device_id) { if (dmanr >= PARPORT_PC_MAX_PORTS) @@ -98,117 +103,145 @@ static __inline__ unsigned int get_dma_residue(unsigned int dmanr) return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info); } -static int ebus_ecpp_p(struct linux_ebus_device *edev) +static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match) { - if (!strcmp(edev->prom_node->name, "ecpp")) - return 1; - if (!strcmp(edev->prom_node->name, "parallel")) { - const char *compat; - - compat = of_get_property(edev->prom_node, - "compatible", NULL); - if (compat && - (!strcmp(compat, "ecpp") || - !strcmp(compat, "ns87317-ecpp") || - !strcmp(compat + 13, "ecpp"))) - return 1; + unsigned long base = op->resource[0].start; + unsigned long config = op->resource[1].start; + unsigned long d_base = op->resource[2].start; + unsigned long d_len; + struct device_node *parent; + struct parport *p; + int slot, err; + + parent = op->node->parent; + if (!strcmp(parent->name, "dma")) { + p = parport_pc_probe_port(base, base + 0x400, + op->irqs[0], PARPORT_DMA_NOFIFO, + op->dev.parent); + if (!p) + return -ENOMEM; + dev_set_drvdata(&op->dev, p); + return 0; } + + for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) { + if (!test_and_set_bit(slot, dma_slot_map)) + break; + } + err = -ENODEV; + if (slot >= PARPORT_PC_MAX_PORTS) + goto out_err; + + spin_lock_init(&sparc_ebus_dmas[slot].info.lock); + + d_len = (op->resource[2].end - d_base) + 1UL; + sparc_ebus_dmas[slot].info.regs = + of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA"); + + if (!sparc_ebus_dmas[slot].info.regs) + goto out_clear_map; + + sparc_ebus_dmas[slot].info.flags = 0; + sparc_ebus_dmas[slot].info.callback = NULL; + sparc_ebus_dmas[slot].info.client_cookie = NULL; + sparc_ebus_dmas[slot].info.irq = 0xdeadbeef; + strcpy(sparc_ebus_dmas[slot].info.name, "parport"); + if (ebus_dma_register(&sparc_ebus_dmas[slot].info)) + goto out_unmap_regs; + + ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1); + + /* Configure IRQ to Push Pull, Level Low */ + /* Enable ECP, set bit 2 of the CTR first */ + outb(0x04, base + 0x02); + ns87303_modify(config, PCR, + PCR_EPP_ENABLE | + PCR_IRQ_ODRAIN, + PCR_ECP_ENABLE | + PCR_ECP_CLK_ENA | + PCR_IRQ_POLAR); + + /* CTR bit 5 controls direction of port */ + ns87303_modify(config, PTR, + 0, PTR_LPT_REG_DIR); + + p = parport_pc_probe_port(base, base + 0x400, + op->irqs[0], + slot, + op->dev.parent); + err = -ENOMEM; + if (!p) + goto out_disable_irq; + + dev_set_drvdata(&op->dev, p); + return 0; + +out_disable_irq: + ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); + ebus_dma_unregister(&sparc_ebus_dmas[slot].info); + +out_unmap_regs: + of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len); + +out_clear_map: + clear_bit(slot, dma_slot_map); + +out_err: + return err; } -static int parport_isa_probe(int count) +static int __devexit ecpp_remove(struct of_device *op) { - struct sparc_isa_bridge *isa_br; - struct sparc_isa_device *isa_dev; - - for_each_isa(isa_br) { - for_each_isadev(isa_dev, isa_br) { - struct sparc_isa_device *child; - unsigned long base; - - if (strcmp(isa_dev->prom_node->name, "dma")) - continue; - - child = isa_dev->child; - while (child) { - if (!strcmp(child->prom_node->name, "parallel")) - break; - child = child->next; - } - if (!child) - continue; - - base = child->resource.start; - - /* No DMA, see commentary in - * asm-sparc64/floppy.h:isa_floppy_init() - */ - if (parport_pc_probe_port(base, base + 0x400, - child->irq, PARPORT_DMA_NOFIFO, - &child->bus->self->dev)) - count++; - } + struct parport *p = dev_get_drvdata(&op->dev); + int slot = p->dma; + + parport_pc_unregister_port(p); + + if (slot != PARPORT_DMA_NOFIFO) { + unsigned long d_base = op->resource[2].start; + unsigned long d_len; + + d_len = (op->resource[2].end - d_base) + 1UL; + + ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); + ebus_dma_unregister(&sparc_ebus_dmas[slot].info); + of_iounmap(&op->resource[2], + sparc_ebus_dmas[slot].info.regs, + d_len); + clear_bit(slot, dma_slot_map); } - return count; + return 0; } -static int parport_pc_find_nonpci_ports (int autoirq, int autodma) +static struct of_device_id ecpp_match[] = { + { + .name = "ecpp", + }, + { + .name = "parallel", + .compatible = "ecpp", + }, + { + .name = "parallel", + .compatible = "ns87317-ecpp", + }, + {}, +}; + +static struct of_platform_driver ecpp_driver = { + .name = "ecpp", + .match_table = ecpp_match, + .probe = ecpp_probe, + .remove = __devexit_p(ecpp_remove), +}; + +static int parport_pc_find_nonpci_ports(int autoirq, int autodma) { - struct linux_ebus *ebus; - struct linux_ebus_device *edev; - int count = 0; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (ebus_ecpp_p(edev)) { - unsigned long base = edev->resource[0].start; - unsigned long config = edev->resource[1].start; - unsigned long d_base = edev->resource[2].start; - unsigned long d_len; - - spin_lock_init(&sparc_ebus_dmas[count].info.lock); - d_len = (edev->resource[2].end - - d_base) + 1; - sparc_ebus_dmas[count].info.regs = - ioremap(d_base, d_len); - if (!sparc_ebus_dmas[count].info.regs) - continue; - sparc_ebus_dmas[count].info.flags = 0; - sparc_ebus_dmas[count].info.callback = NULL; - sparc_ebus_dmas[count].info.client_cookie = NULL; - sparc_ebus_dmas[count].info.irq = 0xdeadbeef; - strcpy(sparc_ebus_dmas[count].info.name, "parport"); - if (ebus_dma_register(&sparc_ebus_dmas[count].info)) - continue; - ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1); - - /* Configure IRQ to Push Pull, Level Low */ - /* Enable ECP, set bit 2 of the CTR first */ - outb(0x04, base + 0x02); - ns87303_modify(config, PCR, - PCR_EPP_ENABLE | - PCR_IRQ_ODRAIN, - PCR_ECP_ENABLE | - PCR_ECP_CLK_ENA | - PCR_IRQ_POLAR); - - /* CTR bit 5 controls direction of port */ - ns87303_modify(config, PTR, - 0, PTR_LPT_REG_DIR); - - if (parport_pc_probe_port(base, base + 0x400, - edev->irqs[0], - count, - &ebus->self->dev)) - count++; - } - } - } + of_register_driver(&ecpp_driver, &of_bus_type); - count = parport_isa_probe(count); - - return count; + return 0; } #endif /* !(_ASM_SPARC64_PARPORT_H */ -- cgit v1.2.3 From cdee99d7461d928815db6219fb14d37f99241d44 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 Jul 2007 13:59:58 -0700 Subject: [SPARC64]: Stop using drivers/char/rtc.c The existing sparc64 mini_rtc driver can handle CMOS based rtcs trivially with just a few lines of code and the simplifies things tremendously. Tested on SB1500. Signed-off-by: David S. Miller --- arch/sparc64/kernel/time.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/char/Kconfig | 2 +- drivers/char/rtc.c | 30 ++++-------------- 3 files changed, 86 insertions(+), 25 deletions(-) diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 592ffcd5760..e340eb401fb 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1434,6 +1434,78 @@ static int bq4802_set_rtc_time(struct rtc_time *time) return 0; } + +static void cmos_get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned char ctrl; + + rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); + rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); + rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); + rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); + rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); + rtc_tm->tm_year = CMOS_READ(RTC_YEAR); + rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); + + ctrl = CMOS_READ(RTC_CONTROL); + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(rtc_tm->tm_sec); + BCD_TO_BIN(rtc_tm->tm_min); + BCD_TO_BIN(rtc_tm->tm_hour); + BCD_TO_BIN(rtc_tm->tm_mday); + BCD_TO_BIN(rtc_tm->tm_mon); + BCD_TO_BIN(rtc_tm->tm_year); + BCD_TO_BIN(rtc_tm->tm_wday); + } + + if (rtc_tm->tm_year <= 69) + rtc_tm->tm_year += 100; + + rtc_tm->tm_mon--; +} + +static int cmos_set_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned char mon, day, hrs, min, sec; + unsigned char save_control, save_freq_select; + unsigned int yrs; + + yrs = rtc_tm->tm_year; + mon = rtc_tm->tm_mon + 1; + day = rtc_tm->tm_mday; + hrs = rtc_tm->tm_hour; + min = rtc_tm->tm_min; + sec = rtc_tm->tm_sec; + + if (yrs >= 100) + yrs -= 100; + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + } + + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return 0; +} #endif /* CONFIG_PCI */ struct mini_rtc_ops { @@ -1456,6 +1528,11 @@ static struct mini_rtc_ops bq4802_rtc_ops = { .get_rtc_time = bq4802_get_rtc_time, .set_rtc_time = bq4802_set_rtc_time, }; + +static struct mini_rtc_ops cmos_rtc_ops = { + .get_rtc_time = cmos_get_rtc_time, + .set_rtc_time = cmos_set_rtc_time, +}; #endif /* CONFIG_PCI */ static struct mini_rtc_ops *mini_rtc_ops; @@ -1583,6 +1660,8 @@ static int __init rtc_mini_init(void) #ifdef CONFIG_PCI else if (bq4802_regs) mini_rtc_ops = &bq4802_rtc_ops; + else if (ds1287_regs) + mini_rtc_ops = &cmos_rtc_ops; #endif /* CONFIG_PCI */ else return -ENODEV; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 4373d7cdc5d..c8dfd18bea4 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -726,7 +726,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390 + depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC64 && (!SPARC32 || PCI) && !FRV && !ARM && !SUPERH && !S390 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 22cf7aa56cc..30c3f54c766 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -86,12 +86,9 @@ #include #endif -#ifdef __sparc__ +#ifdef CONFIG_SPARC32 #include #include -#ifdef __sparc_v9__ -#include -#endif static unsigned long rtc_port; static int rtc_irq = PCI_IRQ_NONE; @@ -930,13 +927,9 @@ static int __init rtc_init(void) unsigned int year, ctrl; char *guess = NULL; #endif -#ifdef __sparc__ +#ifdef CONFIG_SPARC32 struct linux_ebus *ebus; struct linux_ebus_device *edev; -#ifdef __sparc_v9__ - struct sparc_isa_bridge *isa_br; - struct sparc_isa_device *isa_dev; -#endif #else void *r; #ifdef RTC_IRQ @@ -944,7 +937,7 @@ static int __init rtc_init(void) #endif #endif -#ifdef __sparc__ +#ifdef CONFIG_SPARC32 for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if(strcmp(edev->prom_node->name, "rtc") == 0) { @@ -954,17 +947,6 @@ static int __init rtc_init(void) } } } -#ifdef __sparc_v9__ - for_each_isa(isa_br) { - for_each_isadev(isa_dev, isa_br) { - if (strcmp(isa_dev->prom_node->name, "rtc") == 0) { - rtc_port = isa_dev->resource.start; - rtc_irq = isa_dev->irq; - goto found; - } - } - } -#endif rtc_has_irq = 0; printk(KERN_ERR "rtc_init: no PC rtc found\n"); return -EIO; @@ -1020,7 +1002,7 @@ no_irq: #endif -#endif /* __sparc__ vs. others */ +#endif /* CONFIG_SPARC32 vs. others */ if (misc_register(&rtc_dev)) { #ifdef RTC_IRQ @@ -1105,7 +1087,7 @@ static void __exit rtc_exit (void) remove_proc_entry ("driver/rtc", NULL); misc_deregister(&rtc_dev); -#ifdef __sparc__ +#ifdef CONFIG_SPARC32 if (rtc_has_irq) free_irq (rtc_irq, &rtc_port); #else @@ -1117,7 +1099,7 @@ static void __exit rtc_exit (void) if (rtc_has_irq) free_irq (RTC_IRQ, NULL); #endif -#endif /* __sparc__ */ +#endif /* CONFIG_SPARC32 */ } module_init(rtc_init); -- cgit v1.2.3 From f0429bf7a099c28b4806b68812b821ef6d1ddbcb Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Fri, 20 Jul 2007 17:19:56 -0700 Subject: [SPARC64]: fix section mismatch warning in pci_sunv4 Fix following warning: WARNING: vmlinux.o(.text+0x3cf50): Section mismatch: reference to .init.text:page_in_phys_avail (between 'pci_sun4v_pbm_init' and 'sun4v_pci_init') pci_sun4v_pbm_init and sun4v_pci_init was only used under __init context so declare them _init. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_sun4v.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 6b3fe2c1d65..639cf06ca37 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1129,7 +1129,7 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) } #endif /* !(CONFIG_PCI_MSI) */ -static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle) +static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle) { struct pci_pbm_info *pbm; @@ -1163,7 +1163,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node pci_sun4v_msi_init(pbm); } -void sun4v_pci_init(struct device_node *dp, char *model_name) +void __init sun4v_pci_init(struct device_node *dp, char *model_name) { static int hvapi_negotiated = 0; struct pci_controller_info *p; -- cgit v1.2.3 From 1256efd5519a8eca2dfa6039ce5cf58f44d1626d Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Fri, 20 Jul 2007 17:20:56 -0700 Subject: [SPARC64]: fix section mismatch warning in mdesc.c Fix following warning: WARNING: vmlinux.o(.text+0x35264): Section mismatch: reference to .init.text:__alloc_bootmem (between 'mdesc_bootmem_alloc' and 'mdesc_bootmem_free') Rename mdesc_mem_ops to *_ops so modpost ignores __init references and declare mdesc_bootmem_alloc __init since it is only used during __init context. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- arch/sparc64/kernel/mdesc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c index 13a79fe5115..cce4d0ddf5d 100644 --- a/arch/sparc64/kernel/mdesc.c +++ b/arch/sparc64/kernel/mdesc.c @@ -83,7 +83,7 @@ static void mdesc_handle_init(struct mdesc_handle *hp, hp->handle_size = handle_size; } -static struct mdesc_handle *mdesc_bootmem_alloc(unsigned int mdesc_size) +static struct mdesc_handle * __init mdesc_bootmem_alloc(unsigned int mdesc_size) { struct mdesc_handle *hp; unsigned int handle_size, alloc_size; @@ -123,7 +123,7 @@ static void mdesc_bootmem_free(struct mdesc_handle *hp) } } -static struct mdesc_mem_ops bootmem_mdesc_memops = { +static struct mdesc_mem_ops bootmem_mdesc_ops = { .alloc = mdesc_bootmem_alloc, .free = mdesc_bootmem_free, }; @@ -860,7 +860,7 @@ void __init sun4v_mdesc_init(void) printk("MDESC: Size is %lu bytes.\n", len); - hp = mdesc_alloc(len, &bootmem_mdesc_memops); + hp = mdesc_alloc(len, &bootmem_mdesc_ops); if (hp == NULL) { prom_printf("MDESC: alloc of %lu bytes failed.\n", len); prom_halt(); -- cgit v1.2.3