From 2717568e7c44fe7dc3f4f52ea823811cfeede2b5 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 4 Feb 2010 06:57:58 +0000 Subject: usb: r8a66597-hcd: Flush the D-cache for the pipe-in transfer buffers. This implements the same D-cache flushing logic for r8a66597-hcd as Catalin's isp1760 (http://patchwork.kernel.org/patch/76391/) change, with the same note applying here as well: When the HDC driver writes the data to the transfer buffers it pollutes the D-cache (unlike DMA drivers where the device writes the data). If the corresponding pages get mapped into user space, there are no additional cache flushing operations performed and this causes random user space faults on architectures with separate I and D caches (Harvard) or those with aliasing D-cache. This fixes up crashes during USB boot on SH7724 and others: http://marc.info/?l=linux-sh&m=126439837308912&w=2 Reported-by: Goda Yusuke Tested-by: Goda Yusuke Cc: stable@kernel.org Signed-off-by: Paul Mundt Acked-by: Yoshihiro Shimoda --- drivers/usb/host/r8a66597-hcd.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 0ceec123ddf..50a3e2d6a6c 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -35,7 +35,9 @@ #include #include #include +#include #include +#include #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; } } @@ -1283,10 +1299,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) { -- cgit v1.2.3 From 2c940db250c1610d95ea5331dc819b8bd4db96ae Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 4 Feb 2010 06:58:28 +0000 Subject: usb: r8a66597-hcd: Fix up spinlock recursion in root hub polling. The current root hub polling code exhibits a spinlock recursion on the private controller lock. r8a66597_root_hub_control() is called from r8a66597_timer() which grabs the lock and disables IRQs. The following chain emerges: r8a66597_timer() <-- lock taken r8a66597_root_hub_control() r8a66597_check_syssts() usb_hcd_poll_rh_status() <-- acquires the same lock /* insert death here */ The entire chain requires IRQs to be disabled, so we just unlock and relock around the call to usb_hcd_poll_rh_status() while leaving the IRQ state unchanged. Signed-off-by: Paul Mundt Acked-by: Yoshihiro Shimoda --- drivers/usb/host/r8a66597-hcd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 50a3e2d6a6c..bee558aed42 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1022,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)); @@ -1039,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 */ -- cgit v1.2.3 From 142698282ceb6811ad3482c218b7292037cb67ff Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Wed, 27 Jan 2010 20:05:20 +0000 Subject: sh: Correct the offset of the return address in ret_from_exception The address that ret_from_exception and ret_from_irq will return to is found in the stack slot for SPC, not PR. This error was causing the DWARF unwinder to pick up the wrong return address on the stack and then unwind using the unwind tables for the wrong function. While I'm here I might as well add CFI annotations for the other registers since they could be useful when unwinding. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/kernel/entry-common.S | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index f0abd58c3a6..2b15ae60c3a 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -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) ! -- cgit v1.2.3 From 1dca56f13899b9e256f56198026019835aaf9a3a Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Wed, 27 Jan 2010 20:44:59 +0000 Subject: sh: Setup frame pointer in handle_exception path In order to allow the DWARF unwinder to unwind through exceptions we need to setup the frame pointer register (r14). Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh3/entry.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 3f7e2a22c7c..29021bc6749 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -365,6 +365,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) -- cgit v1.2.3 From 944a3438615da65f11e2559840404a2cac5f65ea Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sat, 30 Jan 2010 17:36:20 +0000 Subject: sh: Don't continue unwinding across interrupts Unfortunately, due to poor DWARF info in current toolchains, unwinding through interrutps cannot be done reliably. The problem is that the DWARF info for function epilogues is wrong. Take this standard epilogue sequence, 80003cc4: e3 6f mov r14,r15 80003cc6: 26 4f lds.l @r15+,pr 80003cc8: f6 6e mov.l @r15+,r14 <---- interrupt here 80003cca: f6 6b mov.l @r15+,r11 80003ccc: f6 6a mov.l @r15+,r10 80003cce: f6 69 mov.l @r15+,r9 80003cd0: 0b 00 rts If we take an interrupt at the highlighted point, the DWARF info will bogusly claim that the return address can be found at some offset from the frame pointer, even though the frame pointer was just restored. The worst part is if the unwinder finds a text address at the bogus stack address - unwinding will continue, for a bit, until it finally comes across an unexpected address on the stack and blows up. The only solution is to stop unwinding once we've calculated the function that was executing when the interrupt occurred. This PC can be easily calculated from pt_regs->pc. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/kernel/dwarf.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index 88d28ec3780..e51168064e5 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c @@ -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: -- cgit v1.2.3 From 1af0b2fc676009d9b5b71a82ea6a3c2b20b7ea56 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sat, 30 Jan 2010 17:37:25 +0000 Subject: sh: Remove superfluous setup_frame_reg call There's no need to setup the frame pointer again in call_handle_tlbmiss. The frame pointer will already have been setup in handle_interrupt. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh3/entry.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 29021bc6749..f6a389c996c 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -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 -- cgit v1.2.3