From patchwork Thu Mar 21 06:46:44 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: manjunath.goudar@linaro.org X-Patchwork-Id: 15447 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 249ED23E64 for ; Thu, 21 Mar 2013 06:47:11 +0000 (UTC) Received: from mail-ve0-f174.google.com (mail-ve0-f174.google.com [209.85.128.174]) by fiordland.canonical.com (Postfix) with ESMTP id AF42CA18F9B for ; Thu, 21 Mar 2013 06:47:10 +0000 (UTC) Received: by mail-ve0-f174.google.com with SMTP id pb11so2129943veb.5 for ; Wed, 20 Mar 2013 23:47:10 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:x-received:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=tbz3NZcWPl9egbrMIP2Dp07Xv656xnP69B8/7dD49ys=; b=D2u5LApDg7EExqWfbygbXGZNH5Hvt3hWcXZzVaZSJ7qK6NNSYhJZeqaJ1aWEjb/v0m OGYWNFtijLxW8bMVVUZaDF9oSNATVZmquPG0Ix4SyJnqKDth0Wm/yXqxgQrd98iMC5fQ J5SwWmCSoE5aza0fExi4cUM6mP/C9SXfT777u4PWKDsGSsSEs/QtaAdMnXT+YW7fdTVV LRrZEWCeDT9aRMLre7KdtD/KLJ4zS/D5/h0IsXZBMP4fxkY3jEU4pLP7m2TjERPQYO9L AFKlWKN3DyqSjFLBu6PGEE+QSd9RQzFK17HV8SpNT01bk9CJiIbZ6aPk/INM8HVF1AtJ R6Rw== X-Received: by 10.220.225.200 with SMTP id it8mr11720590vcb.39.1363848430116; Wed, 20 Mar 2013 23:47:10 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.58.233.198 with SMTP id ty6csp47051vec; Wed, 20 Mar 2013 23:47:09 -0700 (PDT) X-Received: by 10.204.240.208 with SMTP id lb16mr12478784bkb.78.1363848428715; Wed, 20 Mar 2013 23:47:08 -0700 (PDT) Received: from mail-bk0-x232.google.com (mail-bk0-x232.google.com [2a00:1450:4008:c01::232]) by mx.google.com with ESMTPS id il5si1856093bkc.30.2013.03.20.23.47.08 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 20 Mar 2013 23:47:08 -0700 (PDT) Received-SPF: neutral (google.com: 2a00:1450:4008:c01::232 is neither permitted nor denied by best guess record for domain of manjunath.goudar@linaro.org) client-ip=2a00:1450:4008:c01::232; Authentication-Results: mx.google.com; spf=neutral (google.com: 2a00:1450:4008:c01::232 is neither permitted nor denied by best guess record for domain of manjunath.goudar@linaro.org) smtp.mail=manjunath.goudar@linaro.org Received: by mail-bk0-f50.google.com with SMTP id jg9so1243481bkc.9 for ; Wed, 20 Mar 2013 23:47:08 -0700 (PDT) X-Received: by 10.204.246.4 with SMTP id lw4mr12332890bkb.36.1363848428048; Wed, 20 Mar 2013 23:47:08 -0700 (PDT) Received: from manjunath-Latitude-E6420.LGE.NET ([203.247.149.152]) by mx.google.com with ESMTPS id ge12sm1077923bkc.19.2013.03.20.23.47.03 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 20 Mar 2013 23:47:07 -0700 (PDT) From: Manjunath Goudar To: manjunath.goudar@linaro.org Cc: arnd@linaro.org, patches@linaro.org Subject: [PATCH 1/2] USB: EHCI: Generic changes to make ehci-tegra a separate driver Date: Thu, 21 Mar 2013 12:16:44 +0530 Message-Id: <1363848405-4229-2-git-send-email-manjunath.goudar@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1363848405-4229-1-git-send-email-manjunath.goudar@linaro.org> References: <1363848405-4229-1-git-send-email-manjunath.goudar@linaro.org> X-Gm-Message-State: ALoCoQnjvEtR7YlYxiKr1O1yG8UkXfXcLxQ3uqYDMJ5iqKjubYTvxAMsYMQ+Dawsys/dKoUV+U99 Note that this changes is part of separating the Tegra host controller driver from ehci-hcd host code. This contains : -Added map_urb_for_dma,unmap_urb_for_dma and hub_control function pointer to override tegra specific function. -handshake function replaced with ehci_handshake and made global. -tdi_reset function replaced ehci_tdi_reset and made gloable. Signed-off-by: Manjunath Goudar Cc: Greg KH Cc: Alan Stern Cc: Grant Likely Cc: Rob Herring Cc: Stephen Warren Cc: Russell King CC: Felipe Balbi Cc: linux-arm-kernel@lists.infradead.org Cc: linux-usb@vger.kernel.org Cc: linux-tegra@vger.kernel.org --- drivers/usb/host/ehci-hcd.c | 28 +++++++++++++++++----------- drivers/usb/host/ehci-hub.c | 9 +++++---- drivers/usb/host/ehci-tegra.c | 14 +++++++------- drivers/usb/host/ehci.h | 23 +++++++++++++++++++++++ 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index a077323..03deeab 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -139,7 +139,7 @@ static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) /*-------------------------------------------------------------------------*/ /* - * handshake - spin reading hc until handshake completes or fails + * ehci_handshake - spin reading hc until handshake completes or fails * @ptr: address of hc register to be read * @mask: bits to look at in result of read * @done: value of those bits when handshake succeeds @@ -155,7 +155,7 @@ static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, +int ehci_handshake (struct ehci_hcd *ehci, void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -172,6 +172,7 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, } while (usec > 0); return -ETIMEDOUT; } +EXPORT_SYMBOL_GPL(ehci_handshake); /* check TDI/ARC silicon is in host mode */ static int tdi_in_host_mode (struct ehci_hcd *ehci) @@ -186,7 +187,7 @@ static int tdi_in_host_mode (struct ehci_hcd *ehci) * Force HC to halt state from unknown (EHCI spec section 2.3). * Must be called with interrupts enabled and the lock not held. */ -static int ehci_halt (struct ehci_hcd *ehci) +int ehci_halt (struct ehci_hcd *ehci) { u32 temp; @@ -212,12 +213,13 @@ static int ehci_halt (struct ehci_hcd *ehci) spin_unlock_irq(&ehci->lock); synchronize_irq(ehci_to_hcd(ehci)->irq); - return handshake(ehci, &ehci->regs->status, + return ehci_handshake(ehci, &ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); } +EXPORT_SYMBOL_GPL(ehci_halt); /* put TDI/ARC silicon into EHCI mode */ -static void tdi_reset (struct ehci_hcd *ehci) +void ehci_tdi_reset (struct ehci_hcd *ehci) { u32 tmp; @@ -231,12 +233,13 @@ static void tdi_reset (struct ehci_hcd *ehci) tmp |= USBMODE_BE; ehci_writel(ehci, tmp, &ehci->regs->usbmode); } +EXPORT_SYMBOL_GPL(ehci_tdi_reset); /* * Reset a non-running (STS_HALT == 1) controller. * Must be called with interrupts enabled and the lock not held. */ -static int ehci_reset (struct ehci_hcd *ehci) +int ehci_reset (struct ehci_hcd *ehci) { int retval; u32 command = ehci_readl(ehci, &ehci->regs->command); @@ -251,7 +254,7 @@ static int ehci_reset (struct ehci_hcd *ehci) ehci_writel(ehci, command, &ehci->regs->command); ehci->rh_state = EHCI_RH_HALTED; ehci->next_statechange = jiffies; - retval = handshake (ehci, &ehci->regs->command, + retval = ehci_handshake(ehci, &ehci->regs->command, CMD_RESET, 0, 250 * 1000); if (ehci->has_hostpc) { @@ -263,7 +266,7 @@ static int ehci_reset (struct ehci_hcd *ehci) return retval; if (ehci_is_TDI(ehci)) - tdi_reset (ehci); + ehci_tdi_reset(ehci); if (ehci->debug) dbgp_external_startup(ehci_to_hcd(ehci)); @@ -272,6 +275,7 @@ static int ehci_reset (struct ehci_hcd *ehci) ehci->resuming_ports = 0; return retval; } +EXPORT_SYMBOL_GPL(ehci_reset); /* * Idle the controller (turn off the schedules). @@ -286,7 +290,8 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /* wait for any schedule enables/disables to take effect */ temp = (ehci->command << 10) & (STS_ASS | STS_PSS); - handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125); + ehci_handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, + 16 * 125); /* then disable anything that's still active */ spin_lock_irq(&ehci->lock); @@ -295,7 +300,8 @@ static void ehci_quiesce (struct ehci_hcd *ehci) spin_unlock_irq(&ehci->lock); /* hardware can take 16 microframes to turn off ... */ - handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125); + ehci_handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, + 16 * 125); } /*-------------------------------------------------------------------------*/ @@ -671,7 +677,7 @@ int ehci_setup(struct usb_hcd *hcd) return retval; if (ehci_is_TDI(ehci)) - tdi_reset(ehci); + ehci_tdi_reset(ehci); ehci_reset(ehci); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 4d3b294..c678a66 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -33,7 +33,7 @@ #ifdef CONFIG_PM -static int ehci_hub_control( +int ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, @@ -695,7 +695,7 @@ ehci_hub_descriptor ( /*-------------------------------------------------------------------------*/ -static int ehci_hub_control ( +int ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, @@ -875,7 +875,7 @@ static int ehci_hub_control ( temp & ~(PORT_RWC_BITS | PORT_RESUME), status_reg); clear_bit(wIndex, &ehci->resuming_ports); - retval = handshake(ehci, status_reg, + retval = ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 2000 /* 2msec */); if (retval != 0) { ehci_err(ehci, @@ -901,7 +901,7 @@ static int ehci_hub_control ( /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ - retval = handshake(ehci, status_reg, + retval = ehci_handshake(ehci, status_reg, PORT_RESET, 0, 1000); if (retval != 0) { ehci_err (ehci, "port %d reset error %d\n", @@ -1115,6 +1115,7 @@ error_exit: spin_unlock_irqrestore (&ehci->lock, flags); return retval; } +EXPORT_SYMBOL_GPL(ehci_hub_control); static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) { diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 568aecc..d2da0d6 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -178,7 +178,7 @@ static int tegra_ehci_hub_control( * If a transaction is in progress, there may be a delay in * suspending the port. Poll until the port is suspended. */ - if (handshake(ehci, status_reg, PORT_SUSPEND, + if (ehci_handshake(ehci, status_reg, PORT_SUSPEND, PORT_SUSPEND, 5000)) pr_err("%s: timeout waiting for SUSPEND\n", __func__); @@ -226,9 +226,9 @@ static int tegra_ehci_hub_control( spin_lock_irqsave(&ehci->lock, flags); /* Poll until the controller clears RESUME and SUSPEND */ - if (handshake(ehci, status_reg, PORT_RESUME, 0, 2000)) + if (ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 2000)) pr_err("%s: timeout waiting for RESUME\n", __func__); - if (handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) + if (ehci_handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) pr_err("%s: timeout waiting for SUSPEND\n", __func__); ehci->reset_done[wIndex-1] = 0; @@ -479,7 +479,7 @@ static int controller_resume(struct device *dev) tegra_ehci_phy_restore_start(hcd->phy, tegra->port_speed); /* Enable host mode */ - tdi_reset(ehci); + ehci_tdi_reset(ehci); /* Enable Port Power */ val = readl(&hw->port_status[0]); @@ -510,14 +510,14 @@ static int controller_resume(struct device *dev) } /* Poll until CCS is enabled */ - if (handshake(ehci, &hw->port_status[0], PORT_CONNECT, + if (ehci_handshake(ehci, &hw->port_status[0], PORT_CONNECT, PORT_CONNECT, 2000)) { pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__); goto restart; } /* Poll until PE is enabled */ - if (handshake(ehci, &hw->port_status[0], PORT_PE, + if (ehci_handshake(ehci, &hw->port_status[0], PORT_PE, PORT_PE, 2000)) { pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__); goto restart; @@ -535,7 +535,7 @@ static int controller_resume(struct device *dev) writel(val, &hw->port_status[0]); /* Wait until port suspend completes */ - if (handshake(ehci, &hw->port_status[0], PORT_SUSPEND, + if (ehci_handshake(ehci, &hw->port_status[0], PORT_SUSPEND, PORT_SUSPEND, 1000)) { pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 139c932..ca15529 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -793,12 +793,35 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) struct ehci_driver_overrides { size_t extra_priv_size; int (*reset)(struct usb_hcd *hcd); + /* + * (optional) these hooks allow an HCD to override the default DMA + * mapping and unmapping routines. In general, they shouldn't be + * necessary unless the host controller has special DMA requirements, + * such as alignment contraints. If these are not specified, the + * general usb_hcd_(un)?map_urb_for_dma functions will be used instead + * (and it may be a good idea to call these functions in your HCD + * implementation) + */ + int (*map_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags); + void (*unmap_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb); + /* root hub support */ + int (*hub_control)(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength); }; extern void ehci_init_driver(struct hc_driver *drv, const struct ehci_driver_overrides *over); extern int ehci_setup(struct usb_hcd *hcd); extern void ehci_shutdown(struct usb_hcd *hcd); +extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec); +extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, + u16 wValue, u16 wIndex, char *buf, + u16 wLength); +extern int ehci_reset(struct ehci_hcd *ehci); +extern int ehci_halt(struct ehci_hcd *ehci); +extern void ehci_tdi_reset(struct ehci_hcd *ehci); #ifdef CONFIG_PM extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);