mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-09-22 12:44:11 +08:00
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.
This commit is contained in:
commit
da8cadb31b
@ -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 @@ retry:
|
|||||||
"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 @@ retry:
|
|||||||
|
|
||||||
/* 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 @@ retry:
|
|||||||
}
|
}
|
||||||
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 @@
|
|||||||
|
|
||||||
#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;
|
||||||
|
|
||||||
int sunserial_console_match(struct console *con, struct device_node *dp,
|
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 __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)
|
|||||||
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 @@
|
|||||||
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
|
|||||||
|
|
||||||
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 @@ out_remove_port:
|
|||||||
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)
|
|||||||
|
|
||||||
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 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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 = {
|
|||||||
.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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 @@
|
|||||||
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 = {
|
|||||||
.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)
|
|||||||
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)
|
|||||||
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 @@ out_unregister_driver:
|
|||||||
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)
|
|||||||
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user