summary refs log tree commit diff
path: root/arch/mn10300
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-12 17:50:34 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-12 17:50:34 -0800
commite37aa63e87bd581f9be5555ed0ba83f5295c92fc (patch)
tree83b57ba86bb9526f08ff4ed99e7e432dfceef4f6 /arch/mn10300
parent9977d9b379cb77e0f67bd6f4563618106e58e11d (diff)
parent76583cffb77533fe564aaf21d184b89a5f419ffe (diff)
downloadlinux-e37aa63e87bd581f9be5555ed0ba83f5295c92fc.tar.gz
Merge tag 'for-linus-20121212' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-mn10300
Pull MN10300 changes from David Howells:
 "miscellaneous MN10300 arch patches.  I've based it on top of Al Viro's
  signal tree - so these patches should be pulled after that."

* tag 'for-linus-20121212' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-mn10300:
  MN10300: Use asm-generic/pci_iomap.h
  MN10300: Get rid of unused variable from ASB2305 PCI code
  MN10300: ASB2305 PCI code needs linux/irq.h
  mn10300/mm/fault.c: Port OOM changes to do_page_fault
  MN10300: Handle cacheable PCI regions in pci_iomap()
  MN10300: fix debug polling in ttySM driver
  MN10300: ttySM: clean up unnecessary casting
  MN10300: fix SMP synchronization between txdma and serial driver
  MN10300: fix serial port vdma irq setup for SMP
  MN10300: cleanup IRQ affinity setting
  MN10300: ttySM: Use memory barriers correctly in circular buffer logic
Diffstat (limited to 'arch/mn10300')
-rw-r--r--arch/mn10300/include/asm/io.h3
-rw-r--r--arch/mn10300/kernel/asm-offsets.c2
-rw-r--r--arch/mn10300/kernel/irq.c50
-rw-r--r--arch/mn10300/kernel/mn10300-serial-low.S9
-rw-r--r--arch/mn10300/kernel/mn10300-serial.c213
-rw-r--r--arch/mn10300/kernel/mn10300-serial.h10
-rw-r--r--arch/mn10300/kernel/smp.c10
-rw-r--r--arch/mn10300/mm/fault.c33
-rw-r--r--arch/mn10300/unit-asb2305/pci-iomap.c35
-rw-r--r--arch/mn10300/unit-asb2305/pci.c5
10 files changed, 234 insertions, 136 deletions
diff --git a/arch/mn10300/include/asm/io.h b/arch/mn10300/include/asm/io.h
index 139df8c53de8..e6ed0d897ccc 100644
--- a/arch/mn10300/include/asm/io.h
+++ b/arch/mn10300/include/asm/io.h
@@ -14,6 +14,7 @@
 #include <asm/page.h> /* I/O is all done through memory accesses */
 #include <asm/cpu-regs.h>
 #include <asm/cacheflush.h>
+#include <asm-generic/pci_iomap.h>
 
 #define mmiowb() do {} while (0)
 
@@ -258,7 +259,7 @@ static inline void __iomem *__ioremap(unsigned long offset, unsigned long size,
 
 static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
 {
-	return (void __iomem *) offset;
+	return (void __iomem *)(offset & ~0x20000000);
 }
 
 /*
diff --git a/arch/mn10300/kernel/asm-offsets.c b/arch/mn10300/kernel/asm-offsets.c
index 96f24fab7de6..47b3bb0c04ff 100644
--- a/arch/mn10300/kernel/asm-offsets.c
+++ b/arch/mn10300/kernel/asm-offsets.c
@@ -96,7 +96,7 @@ void foo(void)
 	OFFSET(__rx_outp,		mn10300_serial_port, rx_outp);
 	OFFSET(__uart_state,		mn10300_serial_port, uart.state);
 	OFFSET(__tx_xchar,		mn10300_serial_port, tx_xchar);
-	OFFSET(__tx_break,		mn10300_serial_port, tx_break);
+	OFFSET(__tx_flags,		mn10300_serial_port, tx_flags);
 	OFFSET(__intr_flags,		mn10300_serial_port, intr_flags);
 	OFFSET(__rx_icr,		mn10300_serial_port, rx_icr);
 	OFFSET(__tx_icr,		mn10300_serial_port, tx_icr);
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
index 35932a8de8b8..6ab3b73efcf8 100644
--- a/arch/mn10300/kernel/irq.c
+++ b/arch/mn10300/kernel/irq.c
@@ -142,57 +142,11 @@ mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask,
 			   bool force)
 {
 	unsigned long flags;
-	int err;
 
 	flags = arch_local_cli_save();
-
-	/* check irq no */
-	switch (d->irq) {
-	case TMJCIRQ:
-	case RESCHEDULE_IPI:
-	case CALL_FUNC_SINGLE_IPI:
-	case LOCAL_TIMER_IPI:
-	case FLUSH_CACHE_IPI:
-	case CALL_FUNCTION_NMI_IPI:
-	case DEBUGGER_NMI_IPI:
-#ifdef CONFIG_MN10300_TTYSM0
-	case SC0RXIRQ:
-	case SC0TXIRQ:
-#ifdef CONFIG_MN10300_TTYSM0_TIMER8
-	case TM8IRQ:
-#elif CONFIG_MN10300_TTYSM0_TIMER2
-	case TM2IRQ:
-#endif /* CONFIG_MN10300_TTYSM0_TIMER8 */
-#endif /* CONFIG_MN10300_TTYSM0 */
-
-#ifdef CONFIG_MN10300_TTYSM1
-	case SC1RXIRQ:
-	case SC1TXIRQ:
-#ifdef CONFIG_MN10300_TTYSM1_TIMER12
-	case TM12IRQ:
-#elif defined(CONFIG_MN10300_TTYSM1_TIMER9)
-	case TM9IRQ:
-#elif defined(CONFIG_MN10300_TTYSM1_TIMER3)
-	case TM3IRQ:
-#endif /* CONFIG_MN10300_TTYSM1_TIMER12 */
-#endif /* CONFIG_MN10300_TTYSM1 */
-
-#ifdef CONFIG_MN10300_TTYSM2
-	case SC2RXIRQ:
-	case SC2TXIRQ:
-	case TM10IRQ:
-#endif /* CONFIG_MN10300_TTYSM2 */
-		err = -1;
-		break;
-
-	default:
-		set_bit(d->irq, irq_affinity_request);
-		err = 0;
-		break;
-	}
-
+	set_bit(d->irq, irq_affinity_request);
 	arch_local_irq_restore(flags);
-	return err;
+	return 0;
 }
 #endif /* CONFIG_SMP */
 
diff --git a/arch/mn10300/kernel/mn10300-serial-low.S b/arch/mn10300/kernel/mn10300-serial-low.S
index dfc1b6f2fa9a..b95e76caf4fa 100644
--- a/arch/mn10300/kernel/mn10300-serial-low.S
+++ b/arch/mn10300/kernel/mn10300-serial-low.S
@@ -118,8 +118,8 @@ ENTRY(mn10300_serial_vdma_tx_handler)
 	movbu	d2,(e3)			# ACK the interrupt
 	movhu	(e3),d2			# flush
 
-	btst	0x01,(__tx_break,a3)	# handle transmit break request
-	bne	mnsc_vdma_tx_break
+	btst	0xFF,(__tx_flags,a3)	# handle transmit flags
+	bne	mnsc_vdma_tx_flags
 
 	movbu	(SCxSTR,e2),d2		# don't try and transmit a char if the
 					# buffer is not empty
@@ -171,10 +171,13 @@ mnsc_vdma_tx_empty:
 	bset	MNSCx_TX_EMPTY,(__intr_flags,a3)
 	bra	mnsc_vdma_tx_done
 
-mnsc_vdma_tx_break:
+mnsc_vdma_tx_flags:
+	btst	MNSCx_TX_STOP,(__tx_flags,a3)
+	bne	mnsc_vdma_tx_stop
 	movhu	(SCxCTR,e2),d2		# turn on break mode
 	or	SC01CTR_BKE,d2
 	movhu	d2,(SCxCTR,e2)
+mnsc_vdma_tx_stop:
 	mov	+(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2
 	movhu	d2,(e3)			# disable transmit interrupts on this
 					# channel
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
index 339cef4c8256..81d5cb9b6569 100644
--- a/arch/mn10300/kernel/mn10300-serial.c
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -408,6 +408,34 @@ static struct irq_chip mn10300_serial_pic = {
 	.irq_unmask	= mn10300_serial_nop,
 };
 
+static void mn10300_serial_low_mask(struct irq_data *d)
+{
+	unsigned long flags;
+	u16 tmp;
+
+	flags = arch_local_cli_save();
+	GxICR(d->irq) = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
+	tmp = GxICR(d->irq); /* flush write buffer */
+	arch_local_irq_restore(flags);
+}
+
+static void mn10300_serial_low_unmask(struct irq_data *d)
+{
+	unsigned long flags;
+	u16 tmp;
+
+	flags = arch_local_cli_save();
+	GxICR(d->irq) =
+		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | GxICR_ENABLE;
+	tmp = GxICR(d->irq); /* flush write buffer */
+	arch_local_irq_restore(flags);
+}
+
+static struct irq_chip mn10300_serial_low_pic = {
+	.name		= "mnserial-low",
+	.irq_mask	= mn10300_serial_low_mask,
+	.irq_unmask	= mn10300_serial_low_unmask,
+};
 
 /*
  * serial virtual DMA interrupt jump table
@@ -416,25 +444,53 @@ struct mn10300_serial_int mn10300_serial_int_tbl[NR_IRQS];
 
 static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port)
 {
-	unsigned long flags;
+	int retries = 100;
 	u16 x;
 
-	flags = arch_local_cli_save();
-	*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
-	x = *port->tx_icr;
-	arch_local_irq_restore(flags);
+	/* nothing to do if irq isn't set up */
+	if (!mn10300_serial_int_tbl[port->tx_irq].port)
+		return;
+
+	port->tx_flags |= MNSCx_TX_STOP;
+	mb();
+
+	/*
+	 * Here we wait for the irq to be disabled. Either it already is
+	 * disabled or we wait some number of retries for the VDMA handler
+	 * to disable it. The retries give the VDMA handler enough time to
+	 * run to completion if it was already in progress. If the VDMA IRQ
+	 * is enabled but the handler is not yet running when arrive here,
+	 * the STOP flag will prevent the handler from conflicting with the
+	 * driver code following this loop.
+	 */
+	while ((*port->tx_icr & GxICR_ENABLE) && retries-- > 0)
+		;
+	if (retries <= 0) {
+		*port->tx_icr =
+			NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
+		x = *port->tx_icr;
+	}
 }
 
 static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port)
 {
-	unsigned long flags;
 	u16 x;
 
-	flags = arch_local_cli_save();
+	/* nothing to do if irq isn't set up */
+	if (!mn10300_serial_int_tbl[port->tx_irq].port)
+		return;
+
+	/* stop vdma irq if not already stopped */
+	if (!(port->tx_flags & MNSCx_TX_STOP))
+		mn10300_serial_dis_tx_intr(port);
+
+	port->tx_flags &= ~MNSCx_TX_STOP;
+	mb();
+
 	*port->tx_icr =
-		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | GxICR_ENABLE;
+		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) |
+		GxICR_ENABLE | GxICR_REQUEST | GxICR_DETECT;
 	x = *port->tx_icr;
-	arch_local_irq_restore(flags);
 }
 
 static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port)
@@ -487,16 +543,17 @@ static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
 
 try_again:
 	/* pull chars out of the hat */
-	ix = port->rx_outp;
-	if (ix == port->rx_inp) {
+	ix = ACCESS_ONCE(port->rx_outp);
+	if (CIRC_CNT(port->rx_inp, ix, MNSC_BUFFER_SIZE) == 0) {
 		if (push && !tty->low_latency)
 			tty_flip_buffer_push(tty);
 		return;
 	}
 
+	smp_read_barrier_depends();
 	ch = port->rx_buffer[ix++];
 	st = port->rx_buffer[ix++];
-	smp_rmb();
+	smp_mb();
 	port->rx_outp = ix & (MNSC_BUFFER_SIZE - 1);
 	port->uart.icount.rx++;
 
@@ -778,8 +835,6 @@ static void mn10300_serial_start_tx(struct uart_port *_port)
 	struct mn10300_serial_port *port =
 		container_of(_port, struct mn10300_serial_port, uart);
 
-	u16 x;
-
 	_enter("%s{%lu}",
 	       port->name,
 	       CIRC_CNT(&port->uart.state->xmit.head,
@@ -787,14 +842,7 @@ static void mn10300_serial_start_tx(struct uart_port *_port)
 			UART_XMIT_SIZE));
 
 	/* kick the virtual DMA controller */
-	arch_local_cli();
-	x = *port->tx_icr;
-	x |= GxICR_ENABLE;
-
-	if (*port->_status & SC01STR_TBF)
-		x &= ~(GxICR_REQUEST | GxICR_DETECT);
-	else
-		x |= GxICR_REQUEST | GxICR_DETECT;
+	mn10300_serial_en_tx_intr(port);
 
 	_debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx",
 	       *port->_control, *port->_intr, *port->_status,
@@ -802,10 +850,6 @@ static void mn10300_serial_start_tx(struct uart_port *_port)
 	       (port->div_timer == MNSCx_DIV_TIMER_8BIT) ?
 	           *(volatile u8 *)port->_tmxbr : *port->_tmxbr,
 	       *port->tx_icr);
-
-	*port->tx_icr = x;
-	x = *port->tx_icr;
-	arch_local_sti();
 }
 
 /*
@@ -815,13 +859,17 @@ static void mn10300_serial_send_xchar(struct uart_port *_port, char ch)
 {
 	struct mn10300_serial_port *port =
 		container_of(_port, struct mn10300_serial_port, uart);
+	unsigned long flags;
 
 	_enter("%s,%02x", port->name, ch);
 
 	if (likely(port->gdbstub)) {
 		port->tx_xchar = ch;
-		if (ch)
+		if (ch) {
+			spin_lock_irqsave(&port->uart.lock, flags);
 			mn10300_serial_en_tx_intr(port);
+			spin_unlock_irqrestore(&port->uart.lock, flags);
+		}
 	}
 }
 
@@ -882,18 +930,21 @@ static void mn10300_serial_break_ctl(struct uart_port *_port, int ctl)
 {
 	struct mn10300_serial_port *port =
 		container_of(_port, struct mn10300_serial_port, uart);
+	unsigned long flags;
 
 	_enter("%s,%d", port->name, ctl);
 
+	spin_lock_irqsave(&port->uart.lock, flags);
 	if (ctl) {
 		/* tell the virtual DMA handler to assert BREAK */
-		port->tx_break = 1;
+		port->tx_flags |= MNSCx_TX_BREAK;
 		mn10300_serial_en_tx_intr(port);
 	} else {
-		port->tx_break = 0;
+		port->tx_flags &= ~MNSCx_TX_BREAK;
 		*port->_control &= ~SC01CTR_BKE;
 		mn10300_serial_en_tx_intr(port);
 	}
+	spin_unlock_irqrestore(&port->uart.lock, flags);
 }
 
 /*
@@ -916,6 +967,7 @@ static int mn10300_serial_startup(struct uart_port *_port)
 		return -ENOMEM;
 
 	port->rx_inp = port->rx_outp = 0;
+	port->tx_flags = 0;
 
 	/* finally, enable the device */
 	*port->_intr = SC01ICR_TI;
@@ -928,22 +980,23 @@ static int mn10300_serial_startup(struct uart_port *_port)
 	pint->port = port;
 	pint->vdma = mn10300_serial_vdma_tx_handler;
 
-	set_intr_level(port->rx_irq,
-		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL));
-	set_intr_level(port->tx_irq,
-		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL));
+	irq_set_chip(port->rx_irq, &mn10300_serial_low_pic);
+	irq_set_chip(port->tx_irq, &mn10300_serial_low_pic);
 	irq_set_chip(port->tm_irq, &mn10300_serial_pic);
 
 	if (request_irq(port->rx_irq, mn10300_serial_interrupt,
-			IRQF_DISABLED, port->rx_name, port) < 0)
+			IRQF_DISABLED | IRQF_NOBALANCING,
+			port->rx_name, port) < 0)
 		goto error;
 
 	if (request_irq(port->tx_irq, mn10300_serial_interrupt,
-			IRQF_DISABLED, port->tx_name, port) < 0)
+			IRQF_DISABLED | IRQF_NOBALANCING,
+			port->tx_name, port) < 0)
 		goto error2;
 
 	if (request_irq(port->tm_irq, mn10300_serial_interrupt,
-			IRQF_DISABLED, port->tm_name, port) < 0)
+			IRQF_DISABLED | IRQF_NOBALANCING,
+			port->tm_name, port) < 0)
 		goto error3;
 	mn10300_serial_mask_ack(port->tm_irq);
 
@@ -964,14 +1017,22 @@ error:
  */
 static void mn10300_serial_shutdown(struct uart_port *_port)
 {
+	unsigned long flags;
 	u16 x;
 	struct mn10300_serial_port *port =
 		container_of(_port, struct mn10300_serial_port, uart);
 
 	_enter("%s", port->name);
 
+	spin_lock_irqsave(&_port->lock, flags);
+	mn10300_serial_dis_tx_intr(port);
+
+	*port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
+	x = *port->rx_icr;
+	port->tx_flags = 0;
+	spin_unlock_irqrestore(&_port->lock, flags);
+
 	/* disable the serial port and its baud rate timer */
-	port->tx_break = 0;
 	*port->_control &= ~(SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE);
 	*port->_tmxmd = 0;
 
@@ -986,12 +1047,8 @@ static void mn10300_serial_shutdown(struct uart_port *_port)
 	free_irq(port->rx_irq, port);
 	free_irq(port->tx_irq, port);
 
-	arch_local_cli();
-	*port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
-	x = *port->rx_icr;
-	*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
-	x = *port->tx_icr;
-	arch_local_sti();
+	mn10300_serial_int_tbl[port->tx_irq].port = NULL;
+	mn10300_serial_int_tbl[port->rx_irq].port = NULL;
 }
 
 /*
@@ -1317,7 +1374,8 @@ timer_okay:
 	if ((new->c_cflag & CREAD) == 0)
 		port->uart.ignore_status_mask |= (1 << TTY_NORMAL);
 
-	scxctr |= *port->_control & (SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE);
+	scxctr |= SC01CTR_TXE | SC01CTR_RXE;
+	scxctr |= *port->_control & SC01CTR_BKE;
 	*port->_control = scxctr;
 
 	spin_unlock_irqrestore(&port->uart.lock, flags);
@@ -1519,17 +1577,24 @@ static void mn10300_serial_console_write(struct console *co,
 {
 	struct mn10300_serial_port *port;
 	unsigned i;
-	u16 scxctr, txicr, tmp;
+	u16 scxctr;
 	u8 tmxmd;
+	unsigned long flags;
+	int locked = 1;
 
 	port = mn10300_serial_ports[co->index];
 
+	local_irq_save(flags);
+	if (port->uart.sysrq) {
+		/* mn10300_serial_interrupt() already took the lock */
+		locked = 0;
+	} else if (oops_in_progress) {
+		locked = spin_trylock(&port->uart.lock);
+	} else
+		spin_lock(&port->uart.lock);
+
 	/* firstly hijack the serial port from the "virtual DMA" controller */
-	arch_local_cli();
-	txicr = *port->tx_icr;
-	*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
-	tmp = *port->tx_icr;
-	arch_local_sti();
+	mn10300_serial_dis_tx_intr(port);
 
 	/* the transmitter may be disabled */
 	scxctr = *port->_control;
@@ -1565,12 +1630,12 @@ static void mn10300_serial_console_write(struct console *co,
 
 		while (*port->_status & SC01STR_TBF)
 			continue;
-		*(u8 *) port->_txb = ch;
+		*port->_txb = ch;
 
 		if (ch == 0x0a) {
 			while (*port->_status & SC01STR_TBF)
 				continue;
-			*(u8 *) port->_txb = 0xd;
+			*port->_txb = 0xd;
 		}
 	}
 
@@ -1583,10 +1648,11 @@ static void mn10300_serial_console_write(struct console *co,
 	if (!(scxctr & SC01CTR_TXE))
 		*port->_control = scxctr;
 
-	arch_local_cli();
-	*port->tx_icr = txicr;
-	tmp = *port->tx_icr;
-	arch_local_sti();
+	mn10300_serial_en_tx_intr(port);
+
+	if (locked)
+		spin_unlock(&port->uart.lock);
+	local_irq_restore(flags);
 }
 
 /*
@@ -1655,18 +1721,29 @@ static int mn10300_serial_poll_get_char(struct uart_port *_port)
 
 	_enter("%s", port->name);
 
-	do {
-		/* pull chars out of the hat */
-		ix = port->rx_outp;
-		if (ix == port->rx_inp)
-			return NO_POLL_CHAR;
+	if (mn10300_serial_int_tbl[port->rx_irq].port != NULL) {
+		do {
+			/* pull chars out of the hat */
+			ix = ACCESS_ONCE(port->rx_outp);
+			if (CIRC_CNT(port->rx_inp, ix, MNSC_BUFFER_SIZE) == 0)
+				return NO_POLL_CHAR;
 
-		ch = port->rx_buffer[ix++];
-		st = port->rx_buffer[ix++];
-		smp_rmb();
-		port->rx_outp = ix & (MNSC_BUFFER_SIZE - 1);
+			smp_read_barrier_depends();
+			ch = port->rx_buffer[ix++];
+			st = port->rx_buffer[ix++];
+			smp_mb();
+			port->rx_outp = ix & (MNSC_BUFFER_SIZE - 1);
 
-	} while (st & (SC01STR_FEF | SC01STR_PEF | SC01STR_OEF));
+		} while (st & (SC01STR_FEF | SC01STR_PEF | SC01STR_OEF));
+	} else {
+		do {
+			st = *port->_status;
+			if (st & (SC01STR_FEF | SC01STR_PEF | SC01STR_OEF))
+				continue;
+		} while (!(st & SC01STR_RBF));
+
+		ch = *port->_rxb;
+	}
 
 	return ch;
 }
@@ -1693,12 +1770,12 @@ static void mn10300_serial_poll_put_char(struct uart_port *_port,
 	tmp = *port->_intr;
 
 	if (ch == 0x0a) {
-		*(u8 *) port->_txb = 0x0d;
+		*port->_txb = 0x0d;
 		while (*port->_status & SC01STR_TBF)
 			continue;
 	}
 
-	*(u8 *) port->_txb = ch;
+	*port->_txb = ch;
 	while (*port->_status & SC01STR_TBF)
 		continue;
 
diff --git a/arch/mn10300/kernel/mn10300-serial.h b/arch/mn10300/kernel/mn10300-serial.h
index 6796499bf789..01791c68ea1f 100644
--- a/arch/mn10300/kernel/mn10300-serial.h
+++ b/arch/mn10300/kernel/mn10300-serial.h
@@ -29,6 +29,10 @@
 #define MNSCx_TX_SPACE		0x04
 #define MNSCx_TX_EMPTY		0x08
 
+/* tx_flags bits */
+#define MNSCx_TX_BREAK		0x01
+#define MNSCx_TX_STOP		0x02
+
 #ifndef __ASSEMBLY__
 
 struct mn10300_serial_port {
@@ -36,7 +40,7 @@ struct mn10300_serial_port {
 	unsigned		rx_inp;		/* pointer to rx input offset */
 	unsigned		rx_outp;	/* pointer to rx output offset */
 	u8			tx_xchar;	/* high-priority XON/XOFF buffer */
-	u8			tx_break;	/* transmit break request */
+	u8			tx_flags;	/* transmit break/stop request */
 	u8			intr_flags;	/* interrupt flags */
 	volatile u16		*rx_icr;	/* Rx interrupt control register */
 	volatile u16		*tx_icr;	/* Tx interrupt control register */
@@ -54,8 +58,8 @@ struct mn10300_serial_port {
 	volatile u16		*_control;	/* control register pointer */
 	volatile u8		*_status;	/* status register pointer */
 	volatile u8		*_intr;		/* interrupt register pointer */
-	volatile void		*_rxb;		/* receive buffer register pointer */
-	volatile void		*_txb;		/* transmit buffer register pointer */
+	volatile u8		*_rxb;		/* receive buffer register pointer */
+	volatile u8		*_txb;		/* transmit buffer register pointer */
 	volatile u16		*_tmicr;	/* timer interrupt control register */
 	volatile u8		*_tmxmd;	/* baud rate timer mode register */
 	volatile u16		*_tmxbr;	/* baud rate timer base register */
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c
index e62c223e4c45..95983cd21e77 100644
--- a/arch/mn10300/kernel/smp.c
+++ b/arch/mn10300/kernel/smp.c
@@ -130,10 +130,12 @@ static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id);
 
 static struct irqaction reschedule_ipi = {
 	.handler	= smp_reschedule_interrupt,
+	.flags		= IRQF_NOBALANCING,
 	.name		= "smp reschedule IPI"
 };
 static struct irqaction call_function_ipi = {
 	.handler	= smp_call_function_interrupt,
+	.flags		= IRQF_NOBALANCING,
 	.name		= "smp call function IPI"
 };
 
@@ -141,7 +143,7 @@ static struct irqaction call_function_ipi = {
 static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id);
 static struct irqaction local_timer_ipi = {
 	.handler	= smp_ipi_timer_interrupt,
-	.flags		= IRQF_DISABLED,
+	.flags		= IRQF_DISABLED | IRQF_NOBALANCING,
 	.name		= "smp local timer IPI"
 };
 #endif
@@ -180,6 +182,7 @@ static void init_ipi(void)
 
 #ifdef CONFIG_MN10300_CACHE_ENABLED
 	/* set up the cache flush IPI */
+	irq_set_chip(FLUSH_CACHE_IPI, &mn10300_ipi_type);
 	flags = arch_local_cli_save();
 	__set_intr_stub(NUM2EXCEP_IRQ_LEVEL(FLUSH_CACHE_GxICR_LV),
 			mn10300_low_ipi_handler);
@@ -189,6 +192,7 @@ static void init_ipi(void)
 #endif
 
 	/* set up the NMI call function IPI */
+	irq_set_chip(CALL_FUNCTION_NMI_IPI, &mn10300_ipi_type);
 	flags = arch_local_cli_save();
 	GxICR(CALL_FUNCTION_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
 	tmp16 = GxICR(CALL_FUNCTION_NMI_IPI);
@@ -199,6 +203,10 @@ static void init_ipi(void)
 	__set_intr_stub(NUM2EXCEP_IRQ_LEVEL(SMP_BOOT_GxICR_LV),
 			mn10300_low_ipi_handler);
 	arch_local_irq_restore(flags);
+
+#ifdef CONFIG_KERNEL_DEBUGGER
+	irq_set_chip(DEBUGGER_NMI_IPI, &mn10300_ipi_type);
+#endif
 }
 
 /**
diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c
index 90f346f7392d..d48a84fd7fae 100644
--- a/arch/mn10300/mm/fault.c
+++ b/arch/mn10300/mm/fault.c
@@ -123,7 +123,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code,
 	struct mm_struct *mm;
 	unsigned long page;
 	siginfo_t info;
-	int write, fault;
+	int fault;
+	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
 #ifdef CONFIG_GDBSTUB
 	/* handle GDB stub causing a fault */
@@ -170,6 +171,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code,
 	if (in_atomic() || !mm)
 		goto no_context;
 
+retry:
 	down_read(&mm->mmap_sem);
 
 	vma = find_vma(mm, address);
@@ -220,7 +222,6 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code,
  */
 good_area:
 	info.si_code = SEGV_ACCERR;
-	write = 0;
 	switch (fault_code & (MMUFCR_xFC_PGINVAL|MMUFCR_xFC_TYPE)) {
 	default:	/* 3: write, present */
 	case MMUFCR_xFC_TYPE_WRITE:
@@ -232,7 +233,7 @@ good_area:
 	case MMUFCR_xFC_PGINVAL | MMUFCR_xFC_TYPE_WRITE:
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
-		write++;
+		flags |= FAULT_FLAG_WRITE;
 		break;
 
 		/* read from protected page */
@@ -251,7 +252,11 @@ good_area:
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
+	fault = handle_mm_fault(mm, vma, address, flags);
+
+	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+		return;
+
 	if (unlikely(fault & VM_FAULT_ERROR)) {
 		if (fault & VM_FAULT_OOM)
 			goto out_of_memory;
@@ -259,10 +264,22 @@ good_area:
 			goto do_sigbus;
 		BUG();
 	}
-	if (fault & VM_FAULT_MAJOR)
-		current->maj_flt++;
-	else
-		current->min_flt++;
+	if (flags & FAULT_FLAG_ALLOW_RETRY) {
+		if (fault & VM_FAULT_MAJOR)
+			current->maj_flt++;
+		else
+			current->min_flt++;
+		if (fault & VM_FAULT_RETRY) {
+			flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+			 /* No need to up_read(&mm->mmap_sem) as we would
+			 * have already released it in __lock_page_or_retry
+			 * in mm/filemap.c.
+			 */
+
+			goto retry;
+		}
+	}
 
 	up_read(&mm->mmap_sem);
 	return;
diff --git a/arch/mn10300/unit-asb2305/pci-iomap.c b/arch/mn10300/unit-asb2305/pci-iomap.c
new file mode 100644
index 000000000000..bd65dae17f32
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci-iomap.c
@@ -0,0 +1,35 @@
+/* ASB2305 PCI I/O mapping handler
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/pci.h>
+#include <linux/module.h>
+
+/*
+ * Create a virtual mapping cookie for a PCI BAR (memory or IO)
+ */
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+	resource_size_t start = pci_resource_start(dev, bar);
+	resource_size_t len = pci_resource_len(dev, bar);
+	unsigned long flags = pci_resource_flags(dev, bar);
+
+	if (!len || !start)
+		return NULL;
+
+	if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM)) {
+		if (flags & IORESOURCE_CACHEABLE && !(flags & IORESOURCE_IO))
+			return ioremap(start, len);
+		else
+			return ioremap_nocache(start, len);
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(pci_iomap);
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
index 6dce9fc2cf3c..e2059486d3f8 100644
--- a/arch/mn10300/unit-asb2305/pci.c
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
+#include <linux/irq.h>
 #include <asm/io.h>
 #include "pci-asb2305.h"
 
@@ -303,9 +304,7 @@ static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
 
 static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
 {
-	struct pci_bus_region region;
-	int i;
-	int limit;
+	int limit, i;
 
 	if (dev->bus->number != 0)
 		return;