diff --git a/arch/mn10300/include/asm/io.h b/arch/mn10300/include/asm/io.h index 139df8c53de..e6ed0d897cc 100644 --- a/arch/mn10300/include/asm/io.h +++ b/arch/mn10300/include/asm/io.h @@ -14,6 +14,7 @@ #include /* I/O is all done through memory accesses */ #include #include +#include #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 96f24fab7de..47b3bb0c04f 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 35932a8de8b..6ab3b73efcf 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 dfc1b6f2fa9..b95e76caf4f 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 339cef4c825..81d5cb9b656 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 6796499bf78..01791c68ea1 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 e62c223e4c4..95983cd21e7 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 90f346f7392..d48a84fd7fa 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 00000000000..bd65dae17f3 --- /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 +#include + +/* + * 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 6dce9fc2cf3..e2059486d3f 100644 --- a/arch/mn10300/unit-asb2305/pci.c +++ b/arch/mn10300/unit-asb2305/pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #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;