Merge branch 'sh/for-2.6.33' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6

* 'sh/for-2.6.33' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6:
  sh: Remove superfluous setup_frame_reg call
  sh: Don't continue unwinding across interrupts
  sh: Setup frame pointer in handle_exception path
  sh: Correct the offset of the return address in ret_from_exception
  usb: r8a66597-hcd: Fix up spinlock recursion in root hub polling.
  usb: r8a66597-hcd: Flush the D-cache for the pipe-in transfer buffers.
This commit is contained in:
Linus Torvalds 2010-02-08 10:09:55 -08:00
commit 8bd73803e1
4 changed files with 58 additions and 14 deletions

View File

@ -132,7 +132,6 @@ ENTRY(tlb_protection_violation_store)
mov #1, r5
call_handle_tlbmiss:
setup_frame_reg
mov.l 1f, r0
mov r5, r8
mov.l @r0, r6
@ -365,6 +364,8 @@ handle_exception:
mov.l @k2, k2 ! read out vector and keep in k2
handle_exception_special:
setup_frame_reg
! Setup return address and jump to exception handler
mov.l 7f, r9 ! fetch return address
stc r2_bank, r0 ! k2 (vector)

View File

@ -540,6 +540,8 @@ void dwarf_free_frame(struct dwarf_frame *frame)
mempool_free(frame, dwarf_frame_pool);
}
extern void ret_from_irq(void);
/**
* dwarf_unwind_stack - unwind the stack
*
@ -678,6 +680,24 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
addr = frame->cfa + reg->addr;
frame->return_addr = __raw_readl(addr);
/*
* Ah, the joys of unwinding through interrupts.
*
* Interrupts are tricky - the DWARF info needs to be _really_
* accurate and unfortunately I'm seeing a lot of bogus DWARF
* info. For example, I've seen interrupts occur in epilogues
* just after the frame pointer (r14) had been restored. The
* problem was that the DWARF info claimed that the CFA could be
* reached by using the value of the frame pointer before it was
* restored.
*
* So until the compiler can be trusted to produce reliable
* DWARF info when it really matters, let's stop unwinding once
* we've calculated the function that was interrupted.
*/
if (prev && prev->pc == (unsigned long)ret_from_irq)
frame->return_addr = 0;
return frame;
bail:

View File

@ -70,8 +70,14 @@ ret_from_exception:
CFI_STARTPROC simple
CFI_DEF_CFA r14, 0
CFI_REL_OFFSET 17, 64
CFI_REL_OFFSET 15, 0
CFI_REL_OFFSET 15, 60
CFI_REL_OFFSET 14, 56
CFI_REL_OFFSET 13, 52
CFI_REL_OFFSET 12, 48
CFI_REL_OFFSET 11, 44
CFI_REL_OFFSET 10, 40
CFI_REL_OFFSET 9, 36
CFI_REL_OFFSET 8, 32
preempt_stop()
ENTRY(ret_from_irq)
!

View File

@ -35,7 +35,9 @@
#include <linux/usb.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/irq.h>
#include <asm/cacheflush.h>
#include "../core/hcd.h"
#include "r8a66597.h"
@ -820,6 +822,26 @@ static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb,
enable_r8a66597_pipe_dma(r8a66597, dev, pipe, urb);
}
static void r8a66597_urb_done(struct r8a66597 *r8a66597, struct urb *urb,
int status)
__releases(r8a66597->lock)
__acquires(r8a66597->lock)
{
if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
void *ptr;
for (ptr = urb->transfer_buffer;
ptr < urb->transfer_buffer + urb->transfer_buffer_length;
ptr += PAGE_SIZE)
flush_dcache_page(virt_to_page(ptr));
}
usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
spin_unlock(&r8a66597->lock);
usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, status);
spin_lock(&r8a66597->lock);
}
/* this function must be called with interrupt disabled */
static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
{
@ -838,15 +860,9 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
list_del(&td->queue);
kfree(td);
if (urb) {
usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
urb);
if (urb)
r8a66597_urb_done(r8a66597, urb, -ENODEV);
spin_unlock(&r8a66597->lock);
usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
-ENODEV);
spin_lock(&r8a66597->lock);
}
break;
}
}
@ -1006,6 +1022,8 @@ static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port,
/* this function must be called with interrupt disabled */
static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
u16 syssts)
__releases(r8a66597->lock)
__acquires(r8a66597->lock)
{
if (syssts == SE0) {
r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port));
@ -1023,7 +1041,9 @@ static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
}
spin_unlock(&r8a66597->lock);
usb_hcd_poll_rh_status(r8a66597_to_hcd(r8a66597));
spin_lock(&r8a66597->lock);
}
/* this function must be called with interrupt disabled */
@ -1283,10 +1303,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock)
if (usb_pipeisoc(urb->pipe))
urb->start_frame = r8a66597_get_frame(hcd);
usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
spin_unlock(&r8a66597->lock);
usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&r8a66597->lock);
r8a66597_urb_done(r8a66597, urb, status);
}
if (restart) {