提交 da8cadb3 编写于 作者: L 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.
......@@ -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)
{
u64 pstate, ver;
u64 pstate, ver, busy_mask;
int nack_busy_id, is_jbus, need_more;
if (cpus_empty(mask))
......@@ -508,14 +508,20 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas
"i" (ASI_INTR_W));
nack_busy_id = 0;
busy_mask = 0;
{
int i;
for_each_cpu_mask(i, mask) {
u64 target = (i << 14) | 0x70;
if (!is_jbus)
if (is_jbus) {
busy_mask |= (0x1UL << (i * 2));
} else {
target |= (nack_busy_id << 24);
busy_mask |= (0x1UL <<
(nack_busy_id * 2));
}
__asm__ __volatile__(
"stxa %%g0, [%0] %1\n\t"
"membar #Sync\n\t"
......@@ -531,15 +537,16 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas
/* Now, poll for completion. */
{
u64 dispatch_stat;
u64 dispatch_stat, nack_mask;
long stuck;
stuck = 100000 * nack_busy_id;
nack_mask = busy_mask << 1;
do {
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (dispatch_stat)
: "i" (ASI_INTR_DISPATCH_STAT));
if (dispatch_stat == 0UL) {
if (!(dispatch_stat & (busy_mask | nack_mask))) {
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate));
if (unlikely(need_more)) {
......@@ -556,12 +563,12 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas
}
if (!--stuck)
break;
} while (dispatch_stat & 0x5555555555555555UL);
} while (dispatch_stat & busy_mask);
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate));
if ((dispatch_stat & ~(0x5555555555555555UL)) == 0) {
if (dispatch_stat & busy_mask) {
/* Busy bits will not clear, continue instead
* of freezing up on this cpu.
*/
......
......@@ -23,11 +23,36 @@
#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)
{
int off;
......@@ -133,8 +158,6 @@ sunserial_console_termios(struct console *con)
con->cflag = cflag;
}
EXPORT_SYMBOL(sunserial_console_termios);
/* Sun serial MOUSE auto baud rate detection. */
static struct mouse_baud_cflag {
int baud;
......
......@@ -22,7 +22,8 @@
extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, 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 *,
struct uart_driver *, int);
......
......@@ -562,16 +562,10 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
port->dev = &op->dev;
sunhv_reg.minor = sunserial_current_minor;
sunhv_reg.nr = 1;
err = uart_register_driver(&sunhv_reg);
err = sunserial_register_minors(&sunhv_reg, 1);
if (err)
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,
&sunhv_reg, port->line);
......@@ -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);
out_unregister_driver:
sunserial_current_minor -= 1;
uart_unregister_driver(&sunhv_reg);
sunserial_unregister_minors(&sunhv_reg, 1);
out_free_con_read_page:
kfree(con_read_page);
......@@ -614,8 +607,7 @@ static int __devexit hv_remove(struct of_device *dev)
uart_remove_one_port(&sunhv_reg, port);
sunserial_current_minor -= 1;
uart_unregister_driver(&sunhv_reg);
sunserial_unregister_minors(&sunhv_reg, 1);
kfree(port);
sunhv_port = NULL;
......
......@@ -832,7 +832,6 @@ static struct uart_driver sunsab_reg = {
};
static struct uart_sunsab_port *sunsab_ports;
static int num_channels;
#ifdef CONFIG_SERIAL_SUNSAB_CONSOLE
......@@ -1102,8 +1101,8 @@ static int __init sunsab_init(void)
{
struct device_node *dp;
int err;
int num_channels = 0;
num_channels = 0;
for_each_node_by_name(dp, "se")
num_channels += 2;
for_each_node_by_name(dp, "serial") {
......@@ -1117,20 +1116,14 @@ static int __init sunsab_init(void)
if (!sunsab_ports)
return -ENOMEM;
sunsab_reg.minor = sunserial_current_minor;
sunsab_reg.nr = num_channels;
sunsab_reg.cons = SUNSAB_CONSOLE();
err = uart_register_driver(&sunsab_reg);
err = sunserial_register_minors(&sunsab_reg, num_channels);
if (err) {
kfree(sunsab_ports);
sunsab_ports = NULL;
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);
......@@ -1139,9 +1132,8 @@ static int __init sunsab_init(void)
static void __exit sunsab_exit(void)
{
of_unregister_driver(&sab_driver);
if (num_channels) {
sunserial_current_minor -= num_channels;
uart_unregister_driver(&sunsab_reg);
if (sunsab_reg.nr) {
sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr);
}
kfree(sunsab_ports);
......
......@@ -1528,14 +1528,12 @@ static struct of_platform_driver su_driver = {
.remove = __devexit_p(su_remove),
};
static int num_uart;
static int __init sunsu_init(void)
{
struct device_node *dp;
int err;
int num_uart = 0;
num_uart = 0;
for_each_node_by_name(dp, "su") {
if (su_get_type(dp) == SU_PORT_PORT)
num_uart++;
......@@ -1552,26 +1550,22 @@ static int __init sunsu_init(void)
}
if (num_uart) {
sunsu_reg.minor = sunserial_current_minor;
sunsu_reg.nr = num_uart;
err = uart_register_driver(&sunsu_reg);
err = sunserial_register_minors(&sunsu_reg, num_uart);
if (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);
if (err && num_uart)
uart_unregister_driver(&sunsu_reg);
sunserial_unregister_minors(&sunsu_reg, num_uart);
return err;
}
static void __exit sunsu_exit(void)
{
if (num_uart)
uart_unregister_driver(&sunsu_reg);
if (sunsu_reg.nr)
sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr);
}
module_init(sunsu_init);
......
......@@ -63,10 +63,6 @@
readb(&((__channel)->control))
#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_DIVISOR 16 /* Divisor this driver uses. */
......@@ -1031,18 +1027,19 @@ static struct uart_driver sunzilog_reg = {
.major = TTY_MAJOR,
};
static int __init sunzilog_alloc_tables(void)
static int __init sunzilog_alloc_tables(int num_sunzilog)
{
struct uart_sunzilog_port *up;
unsigned long size;
int num_channels = num_sunzilog * 2;
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);
if (!sunzilog_port_table)
return -ENOMEM;
for (i = 0; i < NUM_CHANNELS; i++) {
for (i = 0; i < num_channels; i++) {
up = &sunzilog_port_table[i];
spin_lock_init(&up->port.lock);
......@@ -1050,13 +1047,13 @@ static int __init sunzilog_alloc_tables(void)
if (i == 0)
sunzilog_irq_chain = up;
if (i < NUM_CHANNELS - 1)
if (i < num_channels - 1)
up->next = up + 1;
else
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);
if (!sunzilog_chip_regs) {
kfree(sunzilog_port_table);
......@@ -1496,34 +1493,28 @@ static int __init sunzilog_init(void)
struct device_node *dp;
int err, uart_count;
int num_keybms;
int num_sunzilog = 0;
NUM_SUNZILOG = 0;
num_keybms = 0;
for_each_node_by_name(dp, "zs") {
NUM_SUNZILOG++;
num_sunzilog++;
if (of_find_property(dp, "keyboard", NULL))
num_keybms++;
}
uart_count = 0;
if (NUM_SUNZILOG) {
if (num_sunzilog) {
int uart_count;
err = sunzilog_alloc_tables();
err = sunzilog_alloc_tables(num_sunzilog);
if (err)
goto out;
uart_count = (NUM_SUNZILOG * 2) - (2 * num_keybms);
uart_count = (num_sunzilog * 2) - (2 * num_keybms);
sunzilog_reg.nr = uart_count;
sunzilog_reg.minor = sunserial_current_minor;
err = uart_register_driver(&sunzilog_reg);
err = sunserial_register_minors(&sunzilog_reg, uart_count);
if (err)
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);
......@@ -1557,8 +1548,8 @@ static int __init sunzilog_init(void)
of_unregister_driver(&zs_driver);
out_unregister_uart:
if (NUM_SUNZILOG) {
uart_unregister_driver(&sunzilog_reg);
if (num_sunzilog) {
sunserial_unregister_minors(&sunzilog_reg, num_sunzilog);
sunzilog_reg.cons = NULL;
}
......@@ -1590,8 +1581,8 @@ static void __exit sunzilog_exit(void)
zilog_irq = -1;
}
if (NUM_SUNZILOG) {
uart_unregister_driver(&sunzilog_reg);
if (sunzilog_reg.nr) {
sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr);
sunzilog_free_tables();
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册