Merge branch 'tracing/core' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic...
[linux-2.6-block.git] / drivers / usb / host / r8a66597-hcd.c
index b7a661c02bcdb5d3edf0a84b39a50a41f2bf411c..bee558aed42778ce153b5a1db9c4c55376575431 100644 (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"
@@ -216,8 +218,17 @@ static void disable_controller(struct r8a66597 *r8a66597)
 {
        int port;
 
+       /* disable interrupts */
        r8a66597_write(r8a66597, 0, INTENB0);
-       r8a66597_write(r8a66597, 0, INTSTS0);
+       r8a66597_write(r8a66597, 0, INTENB1);
+       r8a66597_write(r8a66597, 0, BRDYENB);
+       r8a66597_write(r8a66597, 0, BEMPENB);
+       r8a66597_write(r8a66597, 0, NRDYENB);
+
+       /* clear status */
+       r8a66597_write(r8a66597, 0, BRDYSTS);
+       r8a66597_write(r8a66597, 0, NRDYSTS);
+       r8a66597_write(r8a66597, 0, BEMPSTS);
 
        for (port = 0; port < r8a66597->max_root_hub; port++)
                r8a66597_disable_port(r8a66597, port);
@@ -811,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)
 {
@@ -829,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;
        }
 }
@@ -997,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));
@@ -1014,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 */
@@ -1274,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) {
@@ -2466,6 +2492,12 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
        r8a66597->rh_timer.data = (unsigned long)r8a66597;
        r8a66597->reg = (unsigned long)reg;
 
+       /* make sure no interrupts are pending */
+       ret = r8a66597_clock_enable(r8a66597);
+       if (ret < 0)
+               goto clean_up3;
+       disable_controller(r8a66597);
+
        for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) {
                INIT_LIST_HEAD(&r8a66597->pipe_queue[i]);
                init_timer(&r8a66597->td_timer[i]);