Commit da8cadb3 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: Fix endless loop in cheetah_xcall_deliver().
  [SERIAL] sparc: Infrastructure to fix section mismatch bugs.
parents 02ec96be 0de56d1a
...@@ -476,7 +476,7 @@ static inline void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, cpuma ...@@ -476,7 +476,7 @@ static inline void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, cpuma
*/ */
static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask)
{ {
u64 pstate, ver; u64 pstate, ver, busy_mask;
int nack_busy_id, is_jbus, need_more; int nack_busy_id, is_jbus, need_more;
if (cpus_empty(mask)) if (cpus_empty(mask))
...@@ -508,14 +508,20 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas ...@@ -508,14 +508,20 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas
"i" (ASI_INTR_W)); "i" (ASI_INTR_W));
nack_busy_id = 0; nack_busy_id = 0;
busy_mask = 0;
{ {
int i; int i;
for_each_cpu_mask(i, mask) { for_each_cpu_mask(i, mask) {
u64 target = (i << 14) | 0x70; u64 target = (i << 14) | 0x70;
if (!is_jbus) if (is_jbus) {
busy_mask |= (0x1UL << (i * 2));
} else {
target |= (nack_busy_id << 24); target |= (nack_busy_id << 24);
busy_mask |= (0x1UL <<
(nack_busy_id * 2));
}
__asm__ __volatile__( __asm__ __volatile__(
"stxa %%g0, [%0] %1\n\t" "stxa %%g0, [%0] %1\n\t"
"membar #Sync\n\t" "membar #Sync\n\t"
...@@ -531,15 +537,16 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas ...@@ -531,15 +537,16 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas
/* Now, poll for completion. */ /* Now, poll for completion. */
{ {
u64 dispatch_stat; u64 dispatch_stat, nack_mask;
long stuck; long stuck;
stuck = 100000 * nack_busy_id; stuck = 100000 * nack_busy_id;
nack_mask = busy_mask << 1;
do { do {
__asm__ __volatile__("ldxa [%%g0] %1, %0" __asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (dispatch_stat) : "=r" (dispatch_stat)
: "i" (ASI_INTR_DISPATCH_STAT)); : "i" (ASI_INTR_DISPATCH_STAT));
if (dispatch_stat == 0UL) { if (!(dispatch_stat & (busy_mask | nack_mask))) {
__asm__ __volatile__("wrpr %0, 0x0, %%pstate" __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate)); : : "r" (pstate));
if (unlikely(need_more)) { if (unlikely(need_more)) {
...@@ -556,12 +563,12 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas ...@@ -556,12 +563,12 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas
} }
if (!--stuck) if (!--stuck)
break; break;
} while (dispatch_stat & 0x5555555555555555UL); } while (dispatch_stat & busy_mask);
__asm__ __volatile__("wrpr %0, 0x0, %%pstate" __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate)); : : "r" (pstate));
if ((dispatch_stat & ~(0x5555555555555555UL)) == 0) { if (dispatch_stat & busy_mask) {
/* Busy bits will not clear, continue instead /* Busy bits will not clear, continue instead
* of freezing up on this cpu. * of freezing up on this cpu.
*/ */
......
...@@ -23,11 +23,36 @@ ...@@ -23,11 +23,36 @@
#include "suncore.h" #include "suncore.h"
int sunserial_current_minor = 64; static int sunserial_current_minor = 64;
EXPORT_SYMBOL(sunserial_current_minor); int sunserial_register_minors(struct uart_driver *drv, int count)
{
int err = 0;
drv->minor = sunserial_current_minor;
drv->nr += count;
/* Register the driver on the first call */
if (drv->nr == count)
err = uart_register_driver(drv);
if (err == 0) {
sunserial_current_minor += count;
drv->tty_driver->name_base = drv->minor - 64;
}
return err;
}
EXPORT_SYMBOL(sunserial_register_minors);
void sunserial_unregister_minors(struct uart_driver *drv, int count)
{
drv->nr -= count;
sunserial_current_minor -= count;
if (drv->nr == 0)
uart_unregister_driver(drv);
}
EXPORT_SYMBOL(sunserial_unregister_minors);
int sunserial_console_match(struct console *con, struct device_node *dp, int __init sunserial_console_match(struct console *con, struct device_node *dp,
struct uart_driver *drv, int line) struct uart_driver *drv, int line)
{ {
int off; int off;
...@@ -133,8 +158,6 @@ sunserial_console_termios(struct console *con) ...@@ -133,8 +158,6 @@ sunserial_console_termios(struct console *con)
con->cflag = cflag; con->cflag = cflag;
} }
EXPORT_SYMBOL(sunserial_console_termios);
/* Sun serial MOUSE auto baud rate detection. */ /* Sun serial MOUSE auto baud rate detection. */
static struct mouse_baud_cflag { static struct mouse_baud_cflag {
int baud; int baud;
......
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *); extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *);
extern int suncore_mouse_baud_detection(unsigned char, int); extern int suncore_mouse_baud_detection(unsigned char, int);
extern int sunserial_current_minor; extern int sunserial_register_minors(struct uart_driver *, int);
extern void sunserial_unregister_minors(struct uart_driver *, int);
extern int sunserial_console_match(struct console *, struct device_node *, extern int sunserial_console_match(struct console *, struct device_node *,
struct uart_driver *, int); struct uart_driver *, int);
......
...@@ -562,16 +562,10 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m ...@@ -562,16 +562,10 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
port->dev = &op->dev; port->dev = &op->dev;
sunhv_reg.minor = sunserial_current_minor; err = sunserial_register_minors(&sunhv_reg, 1);
sunhv_reg.nr = 1;
err = uart_register_driver(&sunhv_reg);
if (err) if (err)
goto out_free_con_read_page; goto out_free_con_read_page;
sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
sunserial_current_minor += 1;
sunserial_console_match(&sunhv_console, op->node, sunserial_console_match(&sunhv_console, op->node,
&sunhv_reg, port->line); &sunhv_reg, port->line);
...@@ -591,8 +585,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m ...@@ -591,8 +585,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
uart_remove_one_port(&sunhv_reg, port); uart_remove_one_port(&sunhv_reg, port);
out_unregister_driver: out_unregister_driver:
sunserial_current_minor -= 1; sunserial_unregister_minors(&sunhv_reg, 1);
uart_unregister_driver(&sunhv_reg);
out_free_con_read_page: out_free_con_read_page:
kfree(con_read_page); kfree(con_read_page);
...@@ -614,8 +607,7 @@ static int __devexit hv_remove(struct of_device *dev) ...@@ -614,8 +607,7 @@ static int __devexit hv_remove(struct of_device *dev)
uart_remove_one_port(&sunhv_reg, port); uart_remove_one_port(&sunhv_reg, port);
sunserial_current_minor -= 1; sunserial_unregister_minors(&sunhv_reg, 1);
uart_unregister_driver(&sunhv_reg);
kfree(port); kfree(port);
sunhv_port = NULL; sunhv_port = NULL;
......
...@@ -832,7 +832,6 @@ static struct uart_driver sunsab_reg = { ...@@ -832,7 +832,6 @@ static struct uart_driver sunsab_reg = {
}; };
static struct uart_sunsab_port *sunsab_ports; static struct uart_sunsab_port *sunsab_ports;
static int num_channels;
#ifdef CONFIG_SERIAL_SUNSAB_CONSOLE #ifdef CONFIG_SERIAL_SUNSAB_CONSOLE
...@@ -1102,8 +1101,8 @@ static int __init sunsab_init(void) ...@@ -1102,8 +1101,8 @@ static int __init sunsab_init(void)
{ {
struct device_node *dp; struct device_node *dp;
int err; int err;
int num_channels = 0;
num_channels = 0;
for_each_node_by_name(dp, "se") for_each_node_by_name(dp, "se")
num_channels += 2; num_channels += 2;
for_each_node_by_name(dp, "serial") { for_each_node_by_name(dp, "serial") {
...@@ -1117,20 +1116,14 @@ static int __init sunsab_init(void) ...@@ -1117,20 +1116,14 @@ static int __init sunsab_init(void)
if (!sunsab_ports) if (!sunsab_ports)
return -ENOMEM; return -ENOMEM;
sunsab_reg.minor = sunserial_current_minor;
sunsab_reg.nr = num_channels;
sunsab_reg.cons = SUNSAB_CONSOLE(); sunsab_reg.cons = SUNSAB_CONSOLE();
err = sunserial_register_minors(&sunsab_reg, num_channels);
err = uart_register_driver(&sunsab_reg);
if (err) { if (err) {
kfree(sunsab_ports); kfree(sunsab_ports);
sunsab_ports = NULL; sunsab_ports = NULL;
return err; return err;
} }
sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
sunserial_current_minor += num_channels;
} }
return of_register_driver(&sab_driver, &of_bus_type); return of_register_driver(&sab_driver, &of_bus_type);
...@@ -1139,9 +1132,8 @@ static int __init sunsab_init(void) ...@@ -1139,9 +1132,8 @@ static int __init sunsab_init(void)
static void __exit sunsab_exit(void) static void __exit sunsab_exit(void)
{ {
of_unregister_driver(&sab_driver); of_unregister_driver(&sab_driver);
if (num_channels) { if (sunsab_reg.nr) {
sunserial_current_minor -= num_channels; sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr);
uart_unregister_driver(&sunsab_reg);
} }
kfree(sunsab_ports); kfree(sunsab_ports);
......
...@@ -1528,14 +1528,12 @@ static struct of_platform_driver su_driver = { ...@@ -1528,14 +1528,12 @@ static struct of_platform_driver su_driver = {
.remove = __devexit_p(su_remove), .remove = __devexit_p(su_remove),
}; };
static int num_uart;
static int __init sunsu_init(void) static int __init sunsu_init(void)
{ {
struct device_node *dp; struct device_node *dp;
int err; int err;
int num_uart = 0;
num_uart = 0;
for_each_node_by_name(dp, "su") { for_each_node_by_name(dp, "su") {
if (su_get_type(dp) == SU_PORT_PORT) if (su_get_type(dp) == SU_PORT_PORT)
num_uart++; num_uart++;
...@@ -1552,26 +1550,22 @@ static int __init sunsu_init(void) ...@@ -1552,26 +1550,22 @@ static int __init sunsu_init(void)
} }
if (num_uart) { if (num_uart) {
sunsu_reg.minor = sunserial_current_minor; err = sunserial_register_minors(&sunsu_reg, num_uart);
sunsu_reg.nr = num_uart;
err = uart_register_driver(&sunsu_reg);
if (err) if (err)
return err; return err;
sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
sunserial_current_minor += num_uart;
} }
err = of_register_driver(&su_driver, &of_bus_type); err = of_register_driver(&su_driver, &of_bus_type);
if (err && num_uart) if (err && num_uart)
uart_unregister_driver(&sunsu_reg); sunserial_unregister_minors(&sunsu_reg, num_uart);
return err; return err;
} }
static void __exit sunsu_exit(void) static void __exit sunsu_exit(void)
{ {
if (num_uart) if (sunsu_reg.nr)
uart_unregister_driver(&sunsu_reg); sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr);
} }
module_init(sunsu_init); module_init(sunsu_init);
......
...@@ -63,10 +63,6 @@ ...@@ -63,10 +63,6 @@
readb(&((__channel)->control)) readb(&((__channel)->control))
#endif #endif
static int num_sunzilog;
#define NUM_SUNZILOG num_sunzilog
#define NUM_CHANNELS (NUM_SUNZILOG * 2)
#define ZS_CLOCK 4915200 /* Zilog input clock rate. */ #define ZS_CLOCK 4915200 /* Zilog input clock rate. */
#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ #define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
...@@ -1031,18 +1027,19 @@ static struct uart_driver sunzilog_reg = { ...@@ -1031,18 +1027,19 @@ static struct uart_driver sunzilog_reg = {
.major = TTY_MAJOR, .major = TTY_MAJOR,
}; };
static int __init sunzilog_alloc_tables(void) static int __init sunzilog_alloc_tables(int num_sunzilog)
{ {
struct uart_sunzilog_port *up; struct uart_sunzilog_port *up;
unsigned long size; unsigned long size;
int num_channels = num_sunzilog * 2;
int i; int i;
size = NUM_CHANNELS * sizeof(struct uart_sunzilog_port); size = num_channels * sizeof(struct uart_sunzilog_port);
sunzilog_port_table = kzalloc(size, GFP_KERNEL); sunzilog_port_table = kzalloc(size, GFP_KERNEL);
if (!sunzilog_port_table) if (!sunzilog_port_table)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < NUM_CHANNELS; i++) { for (i = 0; i < num_channels; i++) {
up = &sunzilog_port_table[i]; up = &sunzilog_port_table[i];
spin_lock_init(&up->port.lock); spin_lock_init(&up->port.lock);
...@@ -1050,13 +1047,13 @@ static int __init sunzilog_alloc_tables(void) ...@@ -1050,13 +1047,13 @@ static int __init sunzilog_alloc_tables(void)
if (i == 0) if (i == 0)
sunzilog_irq_chain = up; sunzilog_irq_chain = up;
if (i < NUM_CHANNELS - 1) if (i < num_channels - 1)
up->next = up + 1; up->next = up + 1;
else else
up->next = NULL; up->next = NULL;
} }
size = NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *); size = num_sunzilog * sizeof(struct zilog_layout __iomem *);
sunzilog_chip_regs = kzalloc(size, GFP_KERNEL); sunzilog_chip_regs = kzalloc(size, GFP_KERNEL);
if (!sunzilog_chip_regs) { if (!sunzilog_chip_regs) {
kfree(sunzilog_port_table); kfree(sunzilog_port_table);
...@@ -1496,34 +1493,28 @@ static int __init sunzilog_init(void) ...@@ -1496,34 +1493,28 @@ static int __init sunzilog_init(void)
struct device_node *dp; struct device_node *dp;
int err, uart_count; int err, uart_count;
int num_keybms; int num_keybms;
int num_sunzilog = 0;
NUM_SUNZILOG = 0;
num_keybms = 0; num_keybms = 0;
for_each_node_by_name(dp, "zs") { for_each_node_by_name(dp, "zs") {
NUM_SUNZILOG++; num_sunzilog++;
if (of_find_property(dp, "keyboard", NULL)) if (of_find_property(dp, "keyboard", NULL))
num_keybms++; num_keybms++;
} }
uart_count = 0; uart_count = 0;
if (NUM_SUNZILOG) { if (num_sunzilog) {
int uart_count; int uart_count;
err = sunzilog_alloc_tables(); err = sunzilog_alloc_tables(num_sunzilog);
if (err) if (err)
goto out; goto out;
uart_count = (NUM_SUNZILOG * 2) - (2 * num_keybms); uart_count = (num_sunzilog * 2) - (2 * num_keybms);
sunzilog_reg.nr = uart_count; err = sunserial_register_minors(&sunzilog_reg, uart_count);
sunzilog_reg.minor = sunserial_current_minor;
err = uart_register_driver(&sunzilog_reg);
if (err) if (err)
goto out_free_tables; goto out_free_tables;
sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
sunserial_current_minor += uart_count;
} }
err = of_register_driver(&zs_driver, &of_bus_type); err = of_register_driver(&zs_driver, &of_bus_type);
...@@ -1557,8 +1548,8 @@ static int __init sunzilog_init(void) ...@@ -1557,8 +1548,8 @@ static int __init sunzilog_init(void)
of_unregister_driver(&zs_driver); of_unregister_driver(&zs_driver);
out_unregister_uart: out_unregister_uart:
if (NUM_SUNZILOG) { if (num_sunzilog) {
uart_unregister_driver(&sunzilog_reg); sunserial_unregister_minors(&sunzilog_reg, num_sunzilog);
sunzilog_reg.cons = NULL; sunzilog_reg.cons = NULL;
} }
...@@ -1590,8 +1581,8 @@ static void __exit sunzilog_exit(void) ...@@ -1590,8 +1581,8 @@ static void __exit sunzilog_exit(void)
zilog_irq = -1; zilog_irq = -1;
} }
if (NUM_SUNZILOG) { if (sunzilog_reg.nr) {
uart_unregister_driver(&sunzilog_reg); sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr);
sunzilog_free_tables(); sunzilog_free_tables();
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment