瀏覽代碼

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.
Linus Torvalds 17 年之前
父節點
當前提交
da8cadb31b
共有 7 個文件被更改,包括 71 次插入71 次删除
  1. 13 6
      arch/sparc64/kernel/smp.c
  2. 28 5
      drivers/serial/suncore.c
  3. 2 1
      drivers/serial/suncore.h
  4. 3 11
      drivers/serial/sunhv.c
  5. 4 12
      drivers/serial/sunsab.c
  6. 5 11
      drivers/serial/sunsu.c
  7. 16 25
      drivers/serial/sunzilog.c

+ 13 - 6
arch/sparc64/kernel/smp.c

@@ -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.
 			 */
 			 */

+ 28 - 5
drivers/serial/suncore.c

@@ -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)
 	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;

+ 2 - 1
drivers/serial/suncore.h

@@ -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);

+ 3 - 11
drivers/serial/sunhv.c

@@ -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;
-	sunhv_reg.nr = 1;
-
-	err = uart_register_driver(&sunhv_reg);
+	err = sunserial_register_minors(&sunhv_reg, 1);
 	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;
-	uart_unregister_driver(&sunhv_reg);
+	sunserial_unregister_minors(&sunhv_reg, 1);
 
 
 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;
-	uart_unregister_driver(&sunhv_reg);
+	sunserial_unregister_minors(&sunhv_reg, 1);
 
 
 	kfree(port);
 	kfree(port);
 	sunhv_port = NULL;
 	sunhv_port = NULL;

+ 4 - 12
drivers/serial/sunsab.c

@@ -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 = uart_register_driver(&sunsab_reg);
+		err = sunserial_register_minors(&sunsab_reg, num_channels);
 		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) {
-		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);
 	kfree(sunsab_ports);

+ 5 - 11
drivers/serial/sunsu.c

@@ -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;
-		sunsu_reg.nr = num_uart;
-		err = uart_register_driver(&sunsu_reg);
+		err = sunserial_register_minors(&sunsu_reg, num_uart);
 		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)
-		uart_unregister_driver(&sunsu_reg);
+	if (sunsu_reg.nr)
+		sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr);
 }
 }
 
 
 module_init(sunsu_init);
 module_init(sunsu_init);

+ 16 - 25
drivers/serial/sunzilog.c

@@ -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;
-		sunzilog_reg.minor = sunserial_current_minor;
-		err = uart_register_driver(&sunzilog_reg);
+		err = sunserial_register_minors(&sunzilog_reg, uart_count);
 		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) {
-		uart_unregister_driver(&sunzilog_reg);
+	if (num_sunzilog) {
+		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) {
-		uart_unregister_driver(&sunzilog_reg);
+	if (sunzilog_reg.nr) {
+		sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr);
 		sunzilog_free_tables();
 		sunzilog_free_tables();
 	}
 	}
 }
 }