1
0
Fork 0
alistair23-linux/drivers/usb/chipidea/host.c

562 lines
14 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* host.c - ChipIdea USB host controller driver
*
* Copyright (c) 2012 Intel Corporation
*
* Author: Alexander Shishkin
*/
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/chipidea.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include "../host/ehci.h"
#include "ci.h"
#include "bits.h"
#include "host.h"
static struct hc_driver __read_mostly ci_ehci_hc_driver;
usb: chipidea: host: add .bus_suspend quirk For chipidea, its resume sequence is not-EHCI compatible, see below description for FPR at portsc. So in order to send SoF in time for remote wakeup sequence(within 3ms), the RUN/STOP bit must be set before the resume signal is ended, but the usb resume code may run after resume signal is ended, so we had to set it at suspend path. Force Port Resume - RW. Default = 0b. 1= Resume detected/driven on port. 0=No resume (K-state) detected/driven on port. Host mode: Software sets this bit to one to drive resume signaling. The Controller sets this bit to '1' if a J-to-K transition is detected while the port is in the Suspend state. When this bit transitions to a '1' because a J-to-K transition is detected, the Port Change Detect bit in the USBSTS register is also set to '1'. This bit will automatically change to '0' after the resume sequence is complete. This behavior is different from EHCI where the controller driver is required to set this bit to a '0' after the resume duration is timed in the driver. Note that when the controller owns the port, the resume sequence follows the defined sequence documented in the USB Specification Revision 2.0. The resume signaling (Full-speed 'K') is driven on the port as long as this bit remains a '1'. This bit will remain a '1' until the port has switched to idle. Writing a '0' has no affect because the port controller will time the resume operation, clear the bit and the port control state switches to HS or FS idle. This field is '0' if Port Power(PP) is '0' in host mode. This bit is not-EHCI compatible. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-02-10 21:44:59 -07:00
static int (*orig_bus_suspend)(struct usb_hcd *hcd);
static int (*orig_bus_resume)(struct usb_hcd *hcd);
struct ehci_ci_priv {
struct regulator *reg_vbus;
usb: chipidea: host: Disable port power only if previously enabled commit c1ffba305dbcf3fb9ca969c20a97acbddc38f8e9 upstream. On shutdown, ehci_power_off() is called unconditionally to power off each port, even if it was never called to power on the port. For chipidea, this results in a call to ehci_ci_portpower() with a request to power off ports even if the port was never powered on. This results in the following warning from the regulator code. WARNING: CPU: 0 PID: 182 at drivers/regulator/core.c:2596 _regulator_disable+0x1a8/0x210 unbalanced disables for usb_otg2_vbus Modules linked in: CPU: 0 PID: 182 Comm: init Not tainted 5.4.6 #1 Hardware name: Freescale i.MX7 Dual (Device Tree) [<c0313658>] (unwind_backtrace) from [<c030d698>] (show_stack+0x10/0x14) [<c030d698>] (show_stack) from [<c1133afc>] (dump_stack+0xe0/0x10c) [<c1133afc>] (dump_stack) from [<c0349098>] (__warn+0xf4/0x10c) [<c0349098>] (__warn) from [<c0349128>] (warn_slowpath_fmt+0x78/0xbc) [<c0349128>] (warn_slowpath_fmt) from [<c09f36ac>] (_regulator_disable+0x1a8/0x210) [<c09f36ac>] (_regulator_disable) from [<c09f374c>] (regulator_disable+0x38/0xe8) [<c09f374c>] (regulator_disable) from [<c0df7bac>] (ehci_ci_portpower+0x38/0xdc) [<c0df7bac>] (ehci_ci_portpower) from [<c0db4fa4>] (ehci_port_power+0x50/0xa4) [<c0db4fa4>] (ehci_port_power) from [<c0db5420>] (ehci_silence_controller+0x5c/0xc4) [<c0db5420>] (ehci_silence_controller) from [<c0db7644>] (ehci_stop+0x3c/0xcc) [<c0db7644>] (ehci_stop) from [<c0d5bdc4>] (usb_remove_hcd+0xe0/0x19c) [<c0d5bdc4>] (usb_remove_hcd) from [<c0df7638>] (host_stop+0x38/0xa8) [<c0df7638>] (host_stop) from [<c0df2f34>] (ci_hdrc_remove+0x44/0xe4) ... Keeping track of the power enable state avoids the warning and traceback. Fixes: c8679a2fb8dec ("usb: chipidea: host: add portpower override") Cc: Michael Grzeschik <m.grzeschik@pengutronix.de> Cc: Peter Chen <peter.chen@freescale.com> Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck <linux@roeck-us.net> Acked-by: Peter Chen <peter.chen@nxp.com> Link: https://lore.kernel.org/r/20191226155754.25451-1-linux@roeck-us.net Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-12-26 08:57:54 -07:00
bool enabled;
};
static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv;
struct device *dev = hcd->self.controller;
struct ci_hdrc *ci = dev_get_drvdata(dev);
int ret = 0;
int port = HCS_N_PORTS(ehci->hcs_params);
usb: chipidea: host: Disable port power only if previously enabled commit c1ffba305dbcf3fb9ca969c20a97acbddc38f8e9 upstream. On shutdown, ehci_power_off() is called unconditionally to power off each port, even if it was never called to power on the port. For chipidea, this results in a call to ehci_ci_portpower() with a request to power off ports even if the port was never powered on. This results in the following warning from the regulator code. WARNING: CPU: 0 PID: 182 at drivers/regulator/core.c:2596 _regulator_disable+0x1a8/0x210 unbalanced disables for usb_otg2_vbus Modules linked in: CPU: 0 PID: 182 Comm: init Not tainted 5.4.6 #1 Hardware name: Freescale i.MX7 Dual (Device Tree) [<c0313658>] (unwind_backtrace) from [<c030d698>] (show_stack+0x10/0x14) [<c030d698>] (show_stack) from [<c1133afc>] (dump_stack+0xe0/0x10c) [<c1133afc>] (dump_stack) from [<c0349098>] (__warn+0xf4/0x10c) [<c0349098>] (__warn) from [<c0349128>] (warn_slowpath_fmt+0x78/0xbc) [<c0349128>] (warn_slowpath_fmt) from [<c09f36ac>] (_regulator_disable+0x1a8/0x210) [<c09f36ac>] (_regulator_disable) from [<c09f374c>] (regulator_disable+0x38/0xe8) [<c09f374c>] (regulator_disable) from [<c0df7bac>] (ehci_ci_portpower+0x38/0xdc) [<c0df7bac>] (ehci_ci_portpower) from [<c0db4fa4>] (ehci_port_power+0x50/0xa4) [<c0db4fa4>] (ehci_port_power) from [<c0db5420>] (ehci_silence_controller+0x5c/0xc4) [<c0db5420>] (ehci_silence_controller) from [<c0db7644>] (ehci_stop+0x3c/0xcc) [<c0db7644>] (ehci_stop) from [<c0d5bdc4>] (usb_remove_hcd+0xe0/0x19c) [<c0d5bdc4>] (usb_remove_hcd) from [<c0df7638>] (host_stop+0x38/0xa8) [<c0df7638>] (host_stop) from [<c0df2f34>] (ci_hdrc_remove+0x44/0xe4) ... Keeping track of the power enable state avoids the warning and traceback. Fixes: c8679a2fb8dec ("usb: chipidea: host: add portpower override") Cc: Michael Grzeschik <m.grzeschik@pengutronix.de> Cc: Peter Chen <peter.chen@freescale.com> Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck <linux@roeck-us.net> Acked-by: Peter Chen <peter.chen@nxp.com> Link: https://lore.kernel.org/r/20191226155754.25451-1-linux@roeck-us.net Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-12-26 08:57:54 -07:00
if (priv->reg_vbus && enable != priv->enabled) {
if (port > 1) {
dev_warn(dev,
"Not support multi-port regulator control\n");
return 0;
}
if (enable)
ret = regulator_enable(priv->reg_vbus);
else
ret = regulator_disable(priv->reg_vbus);
if (ret) {
dev_err(dev,
"Failed to %s vbus regulator, ret=%d\n",
enable ? "enable" : "disable", ret);
return ret;
}
usb: chipidea: host: Disable port power only if previously enabled commit c1ffba305dbcf3fb9ca969c20a97acbddc38f8e9 upstream. On shutdown, ehci_power_off() is called unconditionally to power off each port, even if it was never called to power on the port. For chipidea, this results in a call to ehci_ci_portpower() with a request to power off ports even if the port was never powered on. This results in the following warning from the regulator code. WARNING: CPU: 0 PID: 182 at drivers/regulator/core.c:2596 _regulator_disable+0x1a8/0x210 unbalanced disables for usb_otg2_vbus Modules linked in: CPU: 0 PID: 182 Comm: init Not tainted 5.4.6 #1 Hardware name: Freescale i.MX7 Dual (Device Tree) [<c0313658>] (unwind_backtrace) from [<c030d698>] (show_stack+0x10/0x14) [<c030d698>] (show_stack) from [<c1133afc>] (dump_stack+0xe0/0x10c) [<c1133afc>] (dump_stack) from [<c0349098>] (__warn+0xf4/0x10c) [<c0349098>] (__warn) from [<c0349128>] (warn_slowpath_fmt+0x78/0xbc) [<c0349128>] (warn_slowpath_fmt) from [<c09f36ac>] (_regulator_disable+0x1a8/0x210) [<c09f36ac>] (_regulator_disable) from [<c09f374c>] (regulator_disable+0x38/0xe8) [<c09f374c>] (regulator_disable) from [<c0df7bac>] (ehci_ci_portpower+0x38/0xdc) [<c0df7bac>] (ehci_ci_portpower) from [<c0db4fa4>] (ehci_port_power+0x50/0xa4) [<c0db4fa4>] (ehci_port_power) from [<c0db5420>] (ehci_silence_controller+0x5c/0xc4) [<c0db5420>] (ehci_silence_controller) from [<c0db7644>] (ehci_stop+0x3c/0xcc) [<c0db7644>] (ehci_stop) from [<c0d5bdc4>] (usb_remove_hcd+0xe0/0x19c) [<c0d5bdc4>] (usb_remove_hcd) from [<c0df7638>] (host_stop+0x38/0xa8) [<c0df7638>] (host_stop) from [<c0df2f34>] (ci_hdrc_remove+0x44/0xe4) ... Keeping track of the power enable state avoids the warning and traceback. Fixes: c8679a2fb8dec ("usb: chipidea: host: add portpower override") Cc: Michael Grzeschik <m.grzeschik@pengutronix.de> Cc: Peter Chen <peter.chen@freescale.com> Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck <linux@roeck-us.net> Acked-by: Peter Chen <peter.chen@nxp.com> Link: https://lore.kernel.org/r/20191226155754.25451-1-linux@roeck-us.net Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-12-26 08:57:54 -07:00
priv->enabled = enable;
}
if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) {
/*
* Marvell 28nm HSIC PHY requires forcing the port to HS mode.
* As HSIC is always HS, this should be safe for others.
*/
hw_port_test_set(ci, 5);
hw_port_test_set(ci, 0);
}
return 0;
};
static int ehci_ci_reset(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
struct ci_hdrc *ci = dev_get_drvdata(dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int ret;
ret = ehci_setup(hcd);
if (ret)
return ret;
ehci->need_io_watchdog = 0;
if (ci->platdata->notify_event) {
ret = ci->platdata->notify_event(ci,
CI_HDRC_CONTROLLER_RESET_EVENT);
if (ret)
return ret;
}
ci_platform_configure(ci);
return ret;
}
static const struct ehci_driver_overrides ehci_ci_overrides = {
.extra_priv_size = sizeof(struct ehci_ci_priv),
.port_power = ehci_ci_portpower,
.reset = ehci_ci_reset,
};
static irqreturn_t host_irq(struct ci_hdrc *ci)
{
MLK-11183-1 usb: chipidea: host: fix NULL pointer problem for fast load/unload module The interrupt may occur (due to remove process may block interrupt) after we remove hcd, in that case, we should not call hcd's interrupt handler, otherwise, below NULL pointer dereference will occur, the reason for this is we call free_irq later than hcd's. So after hcd has been removed, we should not call hcd interrupt handler. ci_hdrc ci_hdrc.0: remove, state 1 usb usb1: USB disconnect, device number 1 ci_hdrc ci_hdrc.0: USB bus 1 deregistered [<800691e8>] (handle_irq_event) from [<8006c02c>] (handle_fasteoi_irq+0x84/0x14c) [<8006c02c>] (handle_fasteoi_irq) from [<800687f4>] (generic_handle_irq+0x2c/0x3c) [<800687f4>] (generic_handle_irq) from [<8000ed4c>] (handle_IRQ+0x40/0x90) [<8000ed4c>] (handle_IRQ) from [<8000856c>] (gic_handle_irq+0x2c/0x5c) [<8000856c>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0x80db1f18 to 0x80db1f60) 1f00: 80db1f60 3b9aca00 1f20: 06f86934 0000000d 80dbe1c8 80dbe1c8 ee71e0d0 00000000 06f5bb01 0000000d 1f40: 80db0000 00000000 00000017 80db1f60 00000009 8049c19c 000d0013 ffffffff [<80012240>] (__irq_svc) from [<8049c19c>] (cpuidle_enter_state+0x54/0xe4) [<8049c19c>] (cpuidle_enter_state) from [<8049c2e0>] (cpuidle_idle_call+0xb4/0x14c) [<8049c2e0>] (cpuidle_idle_call) from [<8000f07c>] (arch_cpu_idle+0x8/0x44) [<8000f07c>] (arch_cpu_idle) from [<8006876c>] (cpu_startup_entry+0x100/0x14c) [<8006876c>] (cpu_startup_entry) from [<80d52b10>] (start_kernel+0x350/0x35c) --[ end trace 1160f590a7b228b3 ]-- Unable to handle kernel NULL pointer dereference at virtual address 000000b0 pgd = 80004000 [000000b0] *pgd=00000000 Internal error: Oops: 17 1 PREEMPT SMP ARM Modules linked in: ci_hdrc_imx usbmisc_imx ci_hdrc udc_core ehci_hcd phy_mxs_usb mxc_v4l2_capture ipu_bg_overlay_sdc ipu_still ipu_prp_enc adv7180_tvin ipu_csi_enc v4l2_int_device ipu_fg_overlay_sdc mxc_mlb mxc_dcic evbug [last unloaded: phy_mxs_usb] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.14.38-usb-host-otg-02047-ga4dec77 #13 task: 80dbbae8 ti: 80db0000 task.ti: 80db0000 PC is at usb_hcd_irq+0x4/0x38 LR is at handle_irq_event_percpu+0x50/0x180 pc : [<8040eed8>] lr : [<8006907c>] psr: a00d0193 sp : 80db1e98 ip : fffffffa fp : 00000000 r10: 80e1f13f r9 : d8009900 r8 : 0000004b r7 : 00000000 r6 : 00000000 r5 : d800995c r4 : d8f2dec0 r3 : d2234010 r2 : d2234010 r1 : 00000000 r0 : 0000004b Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 6920004a DAC: 00000015 Process swapper/0 (pid: 0, stack limit = 0x80db0238) Stack: (0x80db1e98 to 0x80db2000) 1e80: d2234010 8006907c 1ea0: 0000004b ee71da00 d8009900 d800995c d8f2dec0 f4a00100 06f5bb01 0000000d 1ec0: 80db0000 800691e8 d8009900 d800995c 00000000 8006c02c 8006bfa8 0000004b 1ee0: 0000004b 800687f4 80dace54 8000ed4c f4a0010c 80db8970 80db1f18 8000856c 1f00: 00000009 8049c19c 000d0013 ffffffff 80db1f4c 80012240 80db1f60 3b9aca00 1f20: 06f86934 0000000d 80dbe1c8 80dbe1c8 ee71e0d0 00000000 06f5bb01 0000000d 1f40: 80db0000 00000000 00000017 80db1f60 00000009 8049c19c 000d0013 ffffffff 1f60: 06f86934 0000000d 80dc4a54 ee71e0d0 80db8574 ee71e0d0 00000000 00000000 1f80: 00000000 80e797f8 80dbe1c8 8049c2e0 00000000 80db0000 80db8574 806fe48c 1fa0: 80db0038 80e1f13d 80e1f13d 8000f07c 00000000 8006876c ffffffff 80d52b10 1fc0: ffffffff ffffffff 80d5258c 00000000 00000000 80d9ef30 00000000 10c53c7d 1fe0: 80db84fc 80d9ef2c 80dbcb80 1000406a 412fc09a 10008074 00000000 00000000 [<8040eed8>] (usb_hcd_irq) from [<8006907c>] (handle_irq_event_percpu+0x50/0x180) [<8006907c>] (handle_irq_event_percpu) from [<800691e8>] (handle_irq_event+0x3c/0x5c) [<800691e8>] (handle_irq_event) from [<8006c02c>] (handle_fasteoi_irq+0x84/0x14c) [<8006c02c>] (handle_fasteoi_irq) from [<800687f4>] (generic_handle_irq+0x2c/0x3c) [<800687f4>] (generic_handle_irq) from [<8000ed4c>] (handle_IRQ+0x40/0x90) [<8000ed4c>] (handle_IRQ) from [<8000856c>] (gic_handle_irq+0x2c/0x5c) [<8000856c>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0x80db1f18 to 0x80db1f60) 1f00: 80db1f60 3b9aca00 1f20: 06f86934 0000000d 80dbe1c8 80dbe1c8 ee71e0d0 00000000 06f5bb01 0000000d 1f40: 80db0000 00000000 00000017 80db1f60 00000009 8049c19c 000d0013 ffffffff [<80012240>] (__irq_svc) from [<8049c19c>] (cpuidle_enter_state+0x54/0xe4) [<8049c19c>] (cpuidle_enter_state) from [<8049c2e0>] (cpuidle_idle_call+0xb4/0x14c) [<8049c2e0>] (cpuidle_idle_call) from [<8000f07c>] (arch_cpu_idle+0x8/0x44) [<8000f07c>] (arch_cpu_idle) from [<8006876c>] (cpu_startup_entry+0x100/0x14c) [<8006876c>] (cpu_startup_entry) from [<80d52b10>] (start_kernel+0x350/0x35c) Code: 11a002a0 03a00001 e12fff1e e92d4008 (e59130b0) --[ end trace 1160f590a7b228b4 ]-- Kernel panic - not syncing: Fatal exception in interrupt CPU2: stopping CPU: 2 PID: 1483 Comm: modprobe Tainted: G D W 3.14.38-usb-host-otg-02047-ga4dec77 #13 [<80014a68>] (unwind_backtrace) from [<80011758>] (show_stack+0x10/0x14) [<80011758>] (show_stack) from [<806f5fe8>] (dump_stack+0x7c/0xbc) [<806f5fe8>] (dump_stack) from [<800139f0>] (handle_IPI+0x144/0x158) [<800139f0>] (handle_IPI) from [<80008598>] (gic_handle_irq+0x58/0x5c) [<80008598>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0xd96c5dc0 to 0xd96c5e08) 5dc0: d800995c 0000004b 00000000 00072004 d8f2dec0 d8009900 d800995c 0000004b 5de0: d800995c a00f0013 00000000 010f2280 fffffffa d96c5e08 00000000 8006926c 5e00: 000f0013 ffffffff [<80012240>] (__irq_svc) from [<8006926c>] (synchronize_irq+0x18/0xa8) [<8006926c>] (synchronize_irq) from [<800696dc>] (__free_irq+0xfc/0x1c4) [<800696dc>] (__free_irq) from [<80069838>] (free_irq+0x4c/0xa4) [<80069838>] (free_irq) from [<8034b760>] (release_nodes+0x16c/0x1cc) [<8034b760>] (release_nodes) from [<803487ec>] (__device_release_driver+0x78/0xcc) [<803487ec>] (__device_release_driver) from [<8034885c>] (device_release_driver+0x1c/0x28) [<8034885c>] (device_release_driver) from [<8034827c>] (bus_remove_device+0xdc/0x108) [<8034827c>] (bus_remove_device) from [<80345788>] (device_del+0x100/0x1a4) [<80345788>] (device_del) from [<8034a218>] (platform_device_del+0x18/0x9c) [<8034a218>] (platform_device_del) from [<8034a2a8>] (platform_device_unregister+0xc/0x20) [<8034a2a8>] (platform_device_unregister) from [<7f61932c>] (ci_hdrc_remove_device+0xc/0x20 [ci_hdrc]) [<7f61932c>] (ci_hdrc_remove_device [ci_hdrc]) from [<7f631260>] (ci_hdrc_imx_remove+0x2c/0xdc [ci_hdrc_imx]) [<7f631260>] (ci_hdrc_imx_remove [ci_hdrc_imx]) from [<8034a350>] (platform_drv_remove+0x18/0x30) [<8034a350>] (platform_drv_remove) from [<803487e4>] (__device_release_driver+0x70/0xcc) [<803487e4>] (__device_release_driver) from [<80348ef4>] (driver_detach+0xac/0xb0) [<80348ef4>] (driver_detach) from [<803484e4>] (bus_remove_driver+0x4c/0xa0) [<803484e4>] (bus_remove_driver) from [<80084158>] (SyS_delete_module+0x11c/0x17c) [<80084158>] (SyS_delete_module) from [<8000e460>] (ret_fast_syscall+0x0/0x30) CPU3: stopping CPU: 3 PID: 0 Comm: swapper/3 Tainted: G D W 3.14.38-usb-host-otg-02047-ga4dec77 #13 [<80014a68>] (unwind_backtrace) from [<80011758>] (show_stack+0x10/0x14) [<80011758>] (show_stack) from [<806f5fe8>] (dump_stack+0x7c/0xbc) [<806f5fe8>] (dump_stack) from [<800139f0>] (handle_IPI+0x144/0x158) [<800139f0>] (handle_IPI) from [<80008598>] (gic_handle_irq+0x58/0x5c) [<80008598>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0xd80b1f50 to 0xd80b1f98) 1f40: d80b1f98 3b9aca00 256aed09 0000000d 1f60: 80dbe1c8 80dbe1c8 ee7360d0 00000000 25477984 0000000d d80b0000 00000000 1f80: 00000017 d80b1f98 00000009 8049c19c 00070013 ffffffff [<80012240>] (__irq_svc) from [<8049c19c>] (cpuidle_enter_state+0x54/0xe4) [<8049c19c>] (cpuidle_enter_state) from [<8049c2e0>] (cpuidle_idle_call+0xb4/0x14c) [<8049c2e0>] (cpuidle_idle_call) from [<8000f07c>] (arch_cpu_idle+0x8/0x44) [<8000f07c>] (arch_cpu_idle) from [<8006876c>] (cpu_startup_entry+0x100/0x14c) [<8006876c>] (cpu_startup_entry) from [<10008624>] (0x10008624) CPU1: stopping Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Li Jun <jun.li@freescale.com> (cherry picked from commit 402f2d38e22007e931dc3dd52a69c0fed88452bf)
2015-07-01 19:41:03 -06:00
if (ci->hcd)
return usb_hcd_irq(ci->irq, ci->hcd);
else
return IRQ_NONE;
}
static int host_start(struct ci_hdrc *ci)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct ehci_ci_priv *priv;
int ret;
if (usb_disabled())
return -ENODEV;
hcd = __usb_create_hcd(&ci_ehci_hc_driver, ci->dev->parent,
ci->dev, dev_name(ci->dev), NULL);
if (!hcd)
return -ENOMEM;
dev_set_drvdata(ci->dev, ci);
hcd->rsrc_start = ci->hw_bank.phys;
hcd->rsrc_len = ci->hw_bank.size;
hcd->regs = ci->hw_bank.abs;
hcd->has_tt = 1;
hcd->power_budget = ci->platdata->power_budget;
hcd->tpl_support = ci->platdata->tpl_support;
if (ci->phy || ci->usb_phy) {
hcd->skip_phy_initialization = 1;
if (ci->usb_phy)
hcd->usb_phy = ci->usb_phy;
}
ehci = hcd_to_ehci(hcd);
ehci->caps = ci->hw_bank.cap;
ehci->has_hostpc = ci->hw_bank.lpm;
ehci->has_tdi_phy_lpm = ci->hw_bank.lpm;
ehci->imx28_write_fix = ci->imx28_write_fix;
priv = (struct ehci_ci_priv *)ehci->priv;
priv->reg_vbus = NULL;
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
if (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON) {
ret = regulator_enable(ci->platdata->reg_vbus);
if (ret) {
dev_err(ci->dev,
"Failed to enable vbus regulator, ret=%d\n",
ret);
goto put_hcd;
}
} else {
priv->reg_vbus = ci->platdata->reg_vbus;
}
}
if (ci->platdata->pins_host)
pinctrl_select_state(ci->platdata->pctl,
ci->platdata->pins_host);
ret = usb_add_hcd(hcd, 0, 0);
if (ret) {
goto disable_reg;
} else {
struct usb_otg *otg = &ci->otg;
ci->hcd = hcd;
if (ci_otg_is_fsm_mode(ci)) {
otg->host = &hcd->self;
hcd->self.otg_port = 1;
}
if (ci->platdata->notify_event &&
(ci->platdata->flags & CI_HDRC_IMX_IS_HSIC))
ci->platdata->notify_event
(ci, CI_HDRC_IMX_HSIC_ACTIVE_EVENT);
}
return ret;
disable_reg:
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci) &&
(ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON))
regulator_disable(ci->platdata->reg_vbus);
put_hcd:
usb_put_hcd(hcd);
return ret;
}
static void host_stop(struct ci_hdrc *ci)
{
struct usb_hcd *hcd = ci->hcd;
usb/chipidea: fix oops on memory allocation failure When CMA fails to initialize in v3.12-rc4, the chipidea driver oopses the kernel while trying to remove and put the HCD which doesn't exist: WARNING: CPU: 0 PID: 6 at /home/rmk/git/linux-rmk/arch/arm/mm/dma-mapping.c:511 __dma_alloc+0x200/0x240() coherent pool not initialised! Modules linked in: CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 3.12.0-rc4+ #56 Workqueue: deferwq deferred_probe_work_func Backtrace: [<c001218c>] (dump_backtrace+0x0/0x10c) from [<c0012328>] (show_stack+0x18/0x1c) r6:c05fd9cc r5:000001ff r4:00000000 r3:df86ad00 [<c0012310>] (show_stack+0x0/0x1c) from [<c05f3a4c>] (dump_stack+0x70/0x8c) [<c05f39dc>] (dump_stack+0x0/0x8c) from [<c00230a8>] (warn_slowpath_common+0x6c/0x8c) r4:df883a60 r3:df86ad00 [<c002303c>] (warn_slowpath_common+0x0/0x8c) from [<c002316c>] (warn_slowpath_fmt+0x38/0x40) r8:ffffffff r7:00001000 r6:c083b808 r5:00000000 r4:df2efe80 [<c0023134>] (warn_slowpath_fmt+0x0/0x40) from [<c00196bc>] (__dma_alloc+0x200/0x240) r3:00000000 r2:c05fda00 [<c00194bc>] (__dma_alloc+0x0/0x240) from [<c001982c>] (arm_dma_alloc+0x88/0xa0) [<c00197a4>] (arm_dma_alloc+0x0/0xa0) from [<c03e2904>] (ehci_setup+0x1f4/0x438) [<c03e2710>] (ehci_setup+0x0/0x438) from [<c03cbd60>] (usb_add_hcd+0x18c/0x664) [<c03cbbd4>] (usb_add_hcd+0x0/0x664) from [<c03e89f4>] (host_start+0xf0/0x180) [<c03e8904>] (host_start+0x0/0x180) from [<c03e7c34>] (ci_hdrc_probe+0x360/0x670 ) r6:df2ef410 r5:00000000 r4:df2c3010 r3:c03e8904 [<c03e78d4>] (ci_hdrc_probe+0x0/0x670) from [<c0311044>] (platform_drv_probe+0x20/0x24) [<c0311024>] (platform_drv_probe+0x0/0x24) from [<c030fcac>] (driver_probe_device+0x9c/0x234) ... ---[ end trace c88ccaf3969e8422 ]--- Unable to handle kernel NULL pointer dereference at virtual address 00000028 pgd = c0004000 [00000028] *pgd=00000000 Internal error: Oops: 17 [#1] SMP ARM Modules linked in: CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 3.12.0-rc4+ #56 Workqueue: deferwq deferred_probe_work_func task: df86ad00 ti: df882000 task.ti: df882000 PC is at usb_remove_hcd+0x10/0x150 LR is at host_stop+0x1c/0x3c pc : [<c03cacec>] lr : [<c03e88e4>] psr: 60000013 sp : df883b50 ip : df883b78 fp : df883b74 r10: c11f4c54 r9 : c0836450 r8 : df30c400 r7 : fffffff4 r6 : df2ef410 r5 : 00000000 r4 : df2c3010 r3 : 00000000 r2 : 00000000 r1 : df86b0a0 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 2f29404a DAC: 00000015 Process kworker/u2:0 (pid: 6, stack limit = 0xdf882240) Stack: (0xdf883b50 to 0xdf884000) ... Backtrace: [<c03cacdc>] (usb_remove_hcd+0x0/0x150) from [<c03e88e4>] (host_stop+0x1c/0x3c) r6:df2ef410 r5:00000000 r4:df2c3010 [<c03e88c8>] (host_stop+0x0/0x3c) from [<c03e8aa0>] (ci_hdrc_host_destroy+0x1c/0x20) r5:00000000 r4:df2c3010 [<c03e8a84>] (ci_hdrc_host_destroy+0x0/0x20) from [<c03e7c80>] (ci_hdrc_probe+0x3ac/0x670) [<c03e78d4>] (ci_hdrc_probe+0x0/0x670) from [<c0311044>] (platform_drv_probe+0x20/0x24) [<c0311024>] (platform_drv_probe+0x0/0x24) from [<c030fcac>] (driver_probe_device+0x9c/0x234) [<c030fc10>] (driver_probe_device+0x0/0x234) from [<c030ff28>] (__device_attach+0x44/0x48) ... ---[ end trace c88ccaf3969e8423 ]--- Fix this so at least we can continue booting and get to a shell prompt. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Tested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-10-16 06:45:15 -06:00
if (hcd) {
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
CI_HDRC_CONTROLLER_STOPPED_EVENT);
usb/chipidea: fix oops on memory allocation failure When CMA fails to initialize in v3.12-rc4, the chipidea driver oopses the kernel while trying to remove and put the HCD which doesn't exist: WARNING: CPU: 0 PID: 6 at /home/rmk/git/linux-rmk/arch/arm/mm/dma-mapping.c:511 __dma_alloc+0x200/0x240() coherent pool not initialised! Modules linked in: CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 3.12.0-rc4+ #56 Workqueue: deferwq deferred_probe_work_func Backtrace: [<c001218c>] (dump_backtrace+0x0/0x10c) from [<c0012328>] (show_stack+0x18/0x1c) r6:c05fd9cc r5:000001ff r4:00000000 r3:df86ad00 [<c0012310>] (show_stack+0x0/0x1c) from [<c05f3a4c>] (dump_stack+0x70/0x8c) [<c05f39dc>] (dump_stack+0x0/0x8c) from [<c00230a8>] (warn_slowpath_common+0x6c/0x8c) r4:df883a60 r3:df86ad00 [<c002303c>] (warn_slowpath_common+0x0/0x8c) from [<c002316c>] (warn_slowpath_fmt+0x38/0x40) r8:ffffffff r7:00001000 r6:c083b808 r5:00000000 r4:df2efe80 [<c0023134>] (warn_slowpath_fmt+0x0/0x40) from [<c00196bc>] (__dma_alloc+0x200/0x240) r3:00000000 r2:c05fda00 [<c00194bc>] (__dma_alloc+0x0/0x240) from [<c001982c>] (arm_dma_alloc+0x88/0xa0) [<c00197a4>] (arm_dma_alloc+0x0/0xa0) from [<c03e2904>] (ehci_setup+0x1f4/0x438) [<c03e2710>] (ehci_setup+0x0/0x438) from [<c03cbd60>] (usb_add_hcd+0x18c/0x664) [<c03cbbd4>] (usb_add_hcd+0x0/0x664) from [<c03e89f4>] (host_start+0xf0/0x180) [<c03e8904>] (host_start+0x0/0x180) from [<c03e7c34>] (ci_hdrc_probe+0x360/0x670 ) r6:df2ef410 r5:00000000 r4:df2c3010 r3:c03e8904 [<c03e78d4>] (ci_hdrc_probe+0x0/0x670) from [<c0311044>] (platform_drv_probe+0x20/0x24) [<c0311024>] (platform_drv_probe+0x0/0x24) from [<c030fcac>] (driver_probe_device+0x9c/0x234) ... ---[ end trace c88ccaf3969e8422 ]--- Unable to handle kernel NULL pointer dereference at virtual address 00000028 pgd = c0004000 [00000028] *pgd=00000000 Internal error: Oops: 17 [#1] SMP ARM Modules linked in: CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 3.12.0-rc4+ #56 Workqueue: deferwq deferred_probe_work_func task: df86ad00 ti: df882000 task.ti: df882000 PC is at usb_remove_hcd+0x10/0x150 LR is at host_stop+0x1c/0x3c pc : [<c03cacec>] lr : [<c03e88e4>] psr: 60000013 sp : df883b50 ip : df883b78 fp : df883b74 r10: c11f4c54 r9 : c0836450 r8 : df30c400 r7 : fffffff4 r6 : df2ef410 r5 : 00000000 r4 : df2c3010 r3 : 00000000 r2 : 00000000 r1 : df86b0a0 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 2f29404a DAC: 00000015 Process kworker/u2:0 (pid: 6, stack limit = 0xdf882240) Stack: (0xdf883b50 to 0xdf884000) ... Backtrace: [<c03cacdc>] (usb_remove_hcd+0x0/0x150) from [<c03e88e4>] (host_stop+0x1c/0x3c) r6:df2ef410 r5:00000000 r4:df2c3010 [<c03e88c8>] (host_stop+0x0/0x3c) from [<c03e8aa0>] (ci_hdrc_host_destroy+0x1c/0x20) r5:00000000 r4:df2c3010 [<c03e8a84>] (ci_hdrc_host_destroy+0x0/0x20) from [<c03e7c80>] (ci_hdrc_probe+0x3ac/0x670) [<c03e78d4>] (ci_hdrc_probe+0x0/0x670) from [<c0311044>] (platform_drv_probe+0x20/0x24) [<c0311024>] (platform_drv_probe+0x0/0x24) from [<c030fcac>] (driver_probe_device+0x9c/0x234) [<c030fc10>] (driver_probe_device+0x0/0x234) from [<c030ff28>] (__device_attach+0x44/0x48) ... ---[ end trace c88ccaf3969e8423 ]--- Fix this so at least we can continue booting and get to a shell prompt. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Tested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-10-16 06:45:15 -06:00
usb_remove_hcd(hcd);
ci->role = CI_ROLE_END;
synchronize_irq(ci->irq);
usb/chipidea: fix oops on memory allocation failure When CMA fails to initialize in v3.12-rc4, the chipidea driver oopses the kernel while trying to remove and put the HCD which doesn't exist: WARNING: CPU: 0 PID: 6 at /home/rmk/git/linux-rmk/arch/arm/mm/dma-mapping.c:511 __dma_alloc+0x200/0x240() coherent pool not initialised! Modules linked in: CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 3.12.0-rc4+ #56 Workqueue: deferwq deferred_probe_work_func Backtrace: [<c001218c>] (dump_backtrace+0x0/0x10c) from [<c0012328>] (show_stack+0x18/0x1c) r6:c05fd9cc r5:000001ff r4:00000000 r3:df86ad00 [<c0012310>] (show_stack+0x0/0x1c) from [<c05f3a4c>] (dump_stack+0x70/0x8c) [<c05f39dc>] (dump_stack+0x0/0x8c) from [<c00230a8>] (warn_slowpath_common+0x6c/0x8c) r4:df883a60 r3:df86ad00 [<c002303c>] (warn_slowpath_common+0x0/0x8c) from [<c002316c>] (warn_slowpath_fmt+0x38/0x40) r8:ffffffff r7:00001000 r6:c083b808 r5:00000000 r4:df2efe80 [<c0023134>] (warn_slowpath_fmt+0x0/0x40) from [<c00196bc>] (__dma_alloc+0x200/0x240) r3:00000000 r2:c05fda00 [<c00194bc>] (__dma_alloc+0x0/0x240) from [<c001982c>] (arm_dma_alloc+0x88/0xa0) [<c00197a4>] (arm_dma_alloc+0x0/0xa0) from [<c03e2904>] (ehci_setup+0x1f4/0x438) [<c03e2710>] (ehci_setup+0x0/0x438) from [<c03cbd60>] (usb_add_hcd+0x18c/0x664) [<c03cbbd4>] (usb_add_hcd+0x0/0x664) from [<c03e89f4>] (host_start+0xf0/0x180) [<c03e8904>] (host_start+0x0/0x180) from [<c03e7c34>] (ci_hdrc_probe+0x360/0x670 ) r6:df2ef410 r5:00000000 r4:df2c3010 r3:c03e8904 [<c03e78d4>] (ci_hdrc_probe+0x0/0x670) from [<c0311044>] (platform_drv_probe+0x20/0x24) [<c0311024>] (platform_drv_probe+0x0/0x24) from [<c030fcac>] (driver_probe_device+0x9c/0x234) ... ---[ end trace c88ccaf3969e8422 ]--- Unable to handle kernel NULL pointer dereference at virtual address 00000028 pgd = c0004000 [00000028] *pgd=00000000 Internal error: Oops: 17 [#1] SMP ARM Modules linked in: CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 3.12.0-rc4+ #56 Workqueue: deferwq deferred_probe_work_func task: df86ad00 ti: df882000 task.ti: df882000 PC is at usb_remove_hcd+0x10/0x150 LR is at host_stop+0x1c/0x3c pc : [<c03cacec>] lr : [<c03e88e4>] psr: 60000013 sp : df883b50 ip : df883b78 fp : df883b74 r10: c11f4c54 r9 : c0836450 r8 : df30c400 r7 : fffffff4 r6 : df2ef410 r5 : 00000000 r4 : df2c3010 r3 : 00000000 r2 : 00000000 r1 : df86b0a0 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 2f29404a DAC: 00000015 Process kworker/u2:0 (pid: 6, stack limit = 0xdf882240) Stack: (0xdf883b50 to 0xdf884000) ... Backtrace: [<c03cacdc>] (usb_remove_hcd+0x0/0x150) from [<c03e88e4>] (host_stop+0x1c/0x3c) r6:df2ef410 r5:00000000 r4:df2c3010 [<c03e88c8>] (host_stop+0x0/0x3c) from [<c03e8aa0>] (ci_hdrc_host_destroy+0x1c/0x20) r5:00000000 r4:df2c3010 [<c03e8a84>] (ci_hdrc_host_destroy+0x0/0x20) from [<c03e7c80>] (ci_hdrc_probe+0x3ac/0x670) [<c03e78d4>] (ci_hdrc_probe+0x0/0x670) from [<c0311044>] (platform_drv_probe+0x20/0x24) [<c0311024>] (platform_drv_probe+0x0/0x24) from [<c030fcac>] (driver_probe_device+0x9c/0x234) [<c030fc10>] (driver_probe_device+0x0/0x234) from [<c030ff28>] (__device_attach+0x44/0x48) ... ---[ end trace c88ccaf3969e8423 ]--- Fix this so at least we can continue booting and get to a shell prompt. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Tested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-10-16 06:45:15 -06:00
usb_put_hcd(hcd);
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci) &&
(ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON))
regulator_disable(ci->platdata->reg_vbus);
usb/chipidea: fix oops on memory allocation failure When CMA fails to initialize in v3.12-rc4, the chipidea driver oopses the kernel while trying to remove and put the HCD which doesn't exist: WARNING: CPU: 0 PID: 6 at /home/rmk/git/linux-rmk/arch/arm/mm/dma-mapping.c:511 __dma_alloc+0x200/0x240() coherent pool not initialised! Modules linked in: CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 3.12.0-rc4+ #56 Workqueue: deferwq deferred_probe_work_func Backtrace: [<c001218c>] (dump_backtrace+0x0/0x10c) from [<c0012328>] (show_stack+0x18/0x1c) r6:c05fd9cc r5:000001ff r4:00000000 r3:df86ad00 [<c0012310>] (show_stack+0x0/0x1c) from [<c05f3a4c>] (dump_stack+0x70/0x8c) [<c05f39dc>] (dump_stack+0x0/0x8c) from [<c00230a8>] (warn_slowpath_common+0x6c/0x8c) r4:df883a60 r3:df86ad00 [<c002303c>] (warn_slowpath_common+0x0/0x8c) from [<c002316c>] (warn_slowpath_fmt+0x38/0x40) r8:ffffffff r7:00001000 r6:c083b808 r5:00000000 r4:df2efe80 [<c0023134>] (warn_slowpath_fmt+0x0/0x40) from [<c00196bc>] (__dma_alloc+0x200/0x240) r3:00000000 r2:c05fda00 [<c00194bc>] (__dma_alloc+0x0/0x240) from [<c001982c>] (arm_dma_alloc+0x88/0xa0) [<c00197a4>] (arm_dma_alloc+0x0/0xa0) from [<c03e2904>] (ehci_setup+0x1f4/0x438) [<c03e2710>] (ehci_setup+0x0/0x438) from [<c03cbd60>] (usb_add_hcd+0x18c/0x664) [<c03cbbd4>] (usb_add_hcd+0x0/0x664) from [<c03e89f4>] (host_start+0xf0/0x180) [<c03e8904>] (host_start+0x0/0x180) from [<c03e7c34>] (ci_hdrc_probe+0x360/0x670 ) r6:df2ef410 r5:00000000 r4:df2c3010 r3:c03e8904 [<c03e78d4>] (ci_hdrc_probe+0x0/0x670) from [<c0311044>] (platform_drv_probe+0x20/0x24) [<c0311024>] (platform_drv_probe+0x0/0x24) from [<c030fcac>] (driver_probe_device+0x9c/0x234) ... ---[ end trace c88ccaf3969e8422 ]--- Unable to handle kernel NULL pointer dereference at virtual address 00000028 pgd = c0004000 [00000028] *pgd=00000000 Internal error: Oops: 17 [#1] SMP ARM Modules linked in: CPU: 0 PID: 6 Comm: kworker/u2:0 Tainted: G W 3.12.0-rc4+ #56 Workqueue: deferwq deferred_probe_work_func task: df86ad00 ti: df882000 task.ti: df882000 PC is at usb_remove_hcd+0x10/0x150 LR is at host_stop+0x1c/0x3c pc : [<c03cacec>] lr : [<c03e88e4>] psr: 60000013 sp : df883b50 ip : df883b78 fp : df883b74 r10: c11f4c54 r9 : c0836450 r8 : df30c400 r7 : fffffff4 r6 : df2ef410 r5 : 00000000 r4 : df2c3010 r3 : 00000000 r2 : 00000000 r1 : df86b0a0 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 2f29404a DAC: 00000015 Process kworker/u2:0 (pid: 6, stack limit = 0xdf882240) Stack: (0xdf883b50 to 0xdf884000) ... Backtrace: [<c03cacdc>] (usb_remove_hcd+0x0/0x150) from [<c03e88e4>] (host_stop+0x1c/0x3c) r6:df2ef410 r5:00000000 r4:df2c3010 [<c03e88c8>] (host_stop+0x0/0x3c) from [<c03e8aa0>] (ci_hdrc_host_destroy+0x1c/0x20) r5:00000000 r4:df2c3010 [<c03e8a84>] (ci_hdrc_host_destroy+0x0/0x20) from [<c03e7c80>] (ci_hdrc_probe+0x3ac/0x670) [<c03e78d4>] (ci_hdrc_probe+0x0/0x670) from [<c0311044>] (platform_drv_probe+0x20/0x24) [<c0311024>] (platform_drv_probe+0x0/0x24) from [<c030fcac>] (driver_probe_device+0x9c/0x234) [<c030fc10>] (driver_probe_device+0x0/0x234) from [<c030ff28>] (__device_attach+0x44/0x48) ... ---[ end trace c88ccaf3969e8423 ]--- Fix this so at least we can continue booting and get to a shell prompt. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Tested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-10-16 06:45:15 -06:00
}
ci->hcd = NULL;
ci->otg.host = NULL;
if (ci->platdata->pins_host && ci->platdata->pins_default)
pinctrl_select_state(ci->platdata->pctl,
ci->platdata->pins_default);
}
bool ci_hdrc_host_has_device(struct ci_hdrc *ci)
{
struct usb_device *roothub;
int i;
if ((ci->role == CI_ROLE_HOST) && ci->hcd) {
roothub = ci->hcd->self.root_hub;
for (i = 0; i < roothub->maxchild; ++i) {
if (usb_hub_find_child(roothub, (i + 1)))
return true;
}
}
return false;
}
static void ci_hdrc_host_save_for_power_lost(struct ci_hdrc *ci)
{
struct ehci_hcd *ehci;
if (!ci->hcd)
return;
ehci = hcd_to_ehci(ci->hcd);
/* save EHCI registers */
ci->pm_usbmode = ehci_readl(ehci, &ehci->regs->usbmode);
ci->pm_command = ehci_readl(ehci, &ehci->regs->command);
ci->pm_command &= ~CMD_RUN;
ci->pm_status = ehci_readl(ehci, &ehci->regs->status);
ci->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable);
ci->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index);
ci->pm_segment = ehci_readl(ehci, &ehci->regs->segment);
ci->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list);
ci->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next);
ci->pm_configured_flag =
ehci_readl(ehci, &ehci->regs->configured_flag);
ci->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
}
static void ci_hdrc_host_restore_from_power_lost(struct ci_hdrc *ci)
{
struct ehci_hcd *ehci;
unsigned long flags;
u32 tmp;
int step_ms;
/*
* If the vbus is off during system suspend, most of devices will pull
* DP up within 200ms when they see vbus, set 1000ms for safety.
*/
int timeout_ms = 1000;
if (!ci->hcd)
return;
hw_controller_reset(ci);
ehci = hcd_to_ehci(ci->hcd);
spin_lock_irqsave(&ehci->lock, flags);
/* Restore EHCI registers */
ehci_writel(ehci, ci->pm_usbmode, &ehci->regs->usbmode);
ehci_writel(ehci, ci->pm_portsc, &ehci->regs->port_status[0]);
ehci_writel(ehci, ci->pm_command, &ehci->regs->command);
ehci_writel(ehci, ci->pm_intr_enable, &ehci->regs->intr_enable);
ehci_writel(ehci, ci->pm_frame_index, &ehci->regs->frame_index);
ehci_writel(ehci, ci->pm_segment, &ehci->regs->segment);
ehci_writel(ehci, ci->pm_frame_list, &ehci->regs->frame_list);
ehci_writel(ehci, ci->pm_async_next, &ehci->regs->async_next);
ehci_writel(ehci, ci->pm_configured_flag,
&ehci->regs->configured_flag);
/* Restore the PHY's connect notifier setting */
if (ci->pm_portsc & PORTSC_HSP)
usb_phy_notify_connect(ci->usb_phy, USB_SPEED_HIGH);
tmp = ehci_readl(ehci, &ehci->regs->command);
tmp |= CMD_RUN;
ehci_writel(ehci, tmp, &ehci->regs->command);
spin_unlock_irqrestore(&ehci->lock, flags);
if (!(ci->pm_portsc & PORTSC_CCS))
return;
for (step_ms = 0; step_ms < timeout_ms; step_ms += 25) {
if (ehci_readl(ehci, &ehci->regs->port_status[0]) & PORTSC_CCS)
break;
msleep(25);
}
}
static void ci_hdrc_host_suspend(struct ci_hdrc *ci)
{
ci_hdrc_host_save_for_power_lost(ci);
}
static void ci_hdrc_host_resume(struct ci_hdrc *ci, bool power_lost)
{
if (power_lost)
ci_hdrc_host_restore_from_power_lost(ci);
}
void ci_hdrc_host_destroy(struct ci_hdrc *ci)
{
MLK-11183-1 usb: chipidea: host: fix NULL pointer problem for fast load/unload module The interrupt may occur (due to remove process may block interrupt) after we remove hcd, in that case, we should not call hcd's interrupt handler, otherwise, below NULL pointer dereference will occur, the reason for this is we call free_irq later than hcd's. So after hcd has been removed, we should not call hcd interrupt handler. ci_hdrc ci_hdrc.0: remove, state 1 usb usb1: USB disconnect, device number 1 ci_hdrc ci_hdrc.0: USB bus 1 deregistered [<800691e8>] (handle_irq_event) from [<8006c02c>] (handle_fasteoi_irq+0x84/0x14c) [<8006c02c>] (handle_fasteoi_irq) from [<800687f4>] (generic_handle_irq+0x2c/0x3c) [<800687f4>] (generic_handle_irq) from [<8000ed4c>] (handle_IRQ+0x40/0x90) [<8000ed4c>] (handle_IRQ) from [<8000856c>] (gic_handle_irq+0x2c/0x5c) [<8000856c>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0x80db1f18 to 0x80db1f60) 1f00: 80db1f60 3b9aca00 1f20: 06f86934 0000000d 80dbe1c8 80dbe1c8 ee71e0d0 00000000 06f5bb01 0000000d 1f40: 80db0000 00000000 00000017 80db1f60 00000009 8049c19c 000d0013 ffffffff [<80012240>] (__irq_svc) from [<8049c19c>] (cpuidle_enter_state+0x54/0xe4) [<8049c19c>] (cpuidle_enter_state) from [<8049c2e0>] (cpuidle_idle_call+0xb4/0x14c) [<8049c2e0>] (cpuidle_idle_call) from [<8000f07c>] (arch_cpu_idle+0x8/0x44) [<8000f07c>] (arch_cpu_idle) from [<8006876c>] (cpu_startup_entry+0x100/0x14c) [<8006876c>] (cpu_startup_entry) from [<80d52b10>] (start_kernel+0x350/0x35c) --[ end trace 1160f590a7b228b3 ]-- Unable to handle kernel NULL pointer dereference at virtual address 000000b0 pgd = 80004000 [000000b0] *pgd=00000000 Internal error: Oops: 17 1 PREEMPT SMP ARM Modules linked in: ci_hdrc_imx usbmisc_imx ci_hdrc udc_core ehci_hcd phy_mxs_usb mxc_v4l2_capture ipu_bg_overlay_sdc ipu_still ipu_prp_enc adv7180_tvin ipu_csi_enc v4l2_int_device ipu_fg_overlay_sdc mxc_mlb mxc_dcic evbug [last unloaded: phy_mxs_usb] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.14.38-usb-host-otg-02047-ga4dec77 #13 task: 80dbbae8 ti: 80db0000 task.ti: 80db0000 PC is at usb_hcd_irq+0x4/0x38 LR is at handle_irq_event_percpu+0x50/0x180 pc : [<8040eed8>] lr : [<8006907c>] psr: a00d0193 sp : 80db1e98 ip : fffffffa fp : 00000000 r10: 80e1f13f r9 : d8009900 r8 : 0000004b r7 : 00000000 r6 : 00000000 r5 : d800995c r4 : d8f2dec0 r3 : d2234010 r2 : d2234010 r1 : 00000000 r0 : 0000004b Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 6920004a DAC: 00000015 Process swapper/0 (pid: 0, stack limit = 0x80db0238) Stack: (0x80db1e98 to 0x80db2000) 1e80: d2234010 8006907c 1ea0: 0000004b ee71da00 d8009900 d800995c d8f2dec0 f4a00100 06f5bb01 0000000d 1ec0: 80db0000 800691e8 d8009900 d800995c 00000000 8006c02c 8006bfa8 0000004b 1ee0: 0000004b 800687f4 80dace54 8000ed4c f4a0010c 80db8970 80db1f18 8000856c 1f00: 00000009 8049c19c 000d0013 ffffffff 80db1f4c 80012240 80db1f60 3b9aca00 1f20: 06f86934 0000000d 80dbe1c8 80dbe1c8 ee71e0d0 00000000 06f5bb01 0000000d 1f40: 80db0000 00000000 00000017 80db1f60 00000009 8049c19c 000d0013 ffffffff 1f60: 06f86934 0000000d 80dc4a54 ee71e0d0 80db8574 ee71e0d0 00000000 00000000 1f80: 00000000 80e797f8 80dbe1c8 8049c2e0 00000000 80db0000 80db8574 806fe48c 1fa0: 80db0038 80e1f13d 80e1f13d 8000f07c 00000000 8006876c ffffffff 80d52b10 1fc0: ffffffff ffffffff 80d5258c 00000000 00000000 80d9ef30 00000000 10c53c7d 1fe0: 80db84fc 80d9ef2c 80dbcb80 1000406a 412fc09a 10008074 00000000 00000000 [<8040eed8>] (usb_hcd_irq) from [<8006907c>] (handle_irq_event_percpu+0x50/0x180) [<8006907c>] (handle_irq_event_percpu) from [<800691e8>] (handle_irq_event+0x3c/0x5c) [<800691e8>] (handle_irq_event) from [<8006c02c>] (handle_fasteoi_irq+0x84/0x14c) [<8006c02c>] (handle_fasteoi_irq) from [<800687f4>] (generic_handle_irq+0x2c/0x3c) [<800687f4>] (generic_handle_irq) from [<8000ed4c>] (handle_IRQ+0x40/0x90) [<8000ed4c>] (handle_IRQ) from [<8000856c>] (gic_handle_irq+0x2c/0x5c) [<8000856c>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0x80db1f18 to 0x80db1f60) 1f00: 80db1f60 3b9aca00 1f20: 06f86934 0000000d 80dbe1c8 80dbe1c8 ee71e0d0 00000000 06f5bb01 0000000d 1f40: 80db0000 00000000 00000017 80db1f60 00000009 8049c19c 000d0013 ffffffff [<80012240>] (__irq_svc) from [<8049c19c>] (cpuidle_enter_state+0x54/0xe4) [<8049c19c>] (cpuidle_enter_state) from [<8049c2e0>] (cpuidle_idle_call+0xb4/0x14c) [<8049c2e0>] (cpuidle_idle_call) from [<8000f07c>] (arch_cpu_idle+0x8/0x44) [<8000f07c>] (arch_cpu_idle) from [<8006876c>] (cpu_startup_entry+0x100/0x14c) [<8006876c>] (cpu_startup_entry) from [<80d52b10>] (start_kernel+0x350/0x35c) Code: 11a002a0 03a00001 e12fff1e e92d4008 (e59130b0) --[ end trace 1160f590a7b228b4 ]-- Kernel panic - not syncing: Fatal exception in interrupt CPU2: stopping CPU: 2 PID: 1483 Comm: modprobe Tainted: G D W 3.14.38-usb-host-otg-02047-ga4dec77 #13 [<80014a68>] (unwind_backtrace) from [<80011758>] (show_stack+0x10/0x14) [<80011758>] (show_stack) from [<806f5fe8>] (dump_stack+0x7c/0xbc) [<806f5fe8>] (dump_stack) from [<800139f0>] (handle_IPI+0x144/0x158) [<800139f0>] (handle_IPI) from [<80008598>] (gic_handle_irq+0x58/0x5c) [<80008598>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0xd96c5dc0 to 0xd96c5e08) 5dc0: d800995c 0000004b 00000000 00072004 d8f2dec0 d8009900 d800995c 0000004b 5de0: d800995c a00f0013 00000000 010f2280 fffffffa d96c5e08 00000000 8006926c 5e00: 000f0013 ffffffff [<80012240>] (__irq_svc) from [<8006926c>] (synchronize_irq+0x18/0xa8) [<8006926c>] (synchronize_irq) from [<800696dc>] (__free_irq+0xfc/0x1c4) [<800696dc>] (__free_irq) from [<80069838>] (free_irq+0x4c/0xa4) [<80069838>] (free_irq) from [<8034b760>] (release_nodes+0x16c/0x1cc) [<8034b760>] (release_nodes) from [<803487ec>] (__device_release_driver+0x78/0xcc) [<803487ec>] (__device_release_driver) from [<8034885c>] (device_release_driver+0x1c/0x28) [<8034885c>] (device_release_driver) from [<8034827c>] (bus_remove_device+0xdc/0x108) [<8034827c>] (bus_remove_device) from [<80345788>] (device_del+0x100/0x1a4) [<80345788>] (device_del) from [<8034a218>] (platform_device_del+0x18/0x9c) [<8034a218>] (platform_device_del) from [<8034a2a8>] (platform_device_unregister+0xc/0x20) [<8034a2a8>] (platform_device_unregister) from [<7f61932c>] (ci_hdrc_remove_device+0xc/0x20 [ci_hdrc]) [<7f61932c>] (ci_hdrc_remove_device [ci_hdrc]) from [<7f631260>] (ci_hdrc_imx_remove+0x2c/0xdc [ci_hdrc_imx]) [<7f631260>] (ci_hdrc_imx_remove [ci_hdrc_imx]) from [<8034a350>] (platform_drv_remove+0x18/0x30) [<8034a350>] (platform_drv_remove) from [<803487e4>] (__device_release_driver+0x70/0xcc) [<803487e4>] (__device_release_driver) from [<80348ef4>] (driver_detach+0xac/0xb0) [<80348ef4>] (driver_detach) from [<803484e4>] (bus_remove_driver+0x4c/0xa0) [<803484e4>] (bus_remove_driver) from [<80084158>] (SyS_delete_module+0x11c/0x17c) [<80084158>] (SyS_delete_module) from [<8000e460>] (ret_fast_syscall+0x0/0x30) CPU3: stopping CPU: 3 PID: 0 Comm: swapper/3 Tainted: G D W 3.14.38-usb-host-otg-02047-ga4dec77 #13 [<80014a68>] (unwind_backtrace) from [<80011758>] (show_stack+0x10/0x14) [<80011758>] (show_stack) from [<806f5fe8>] (dump_stack+0x7c/0xbc) [<806f5fe8>] (dump_stack) from [<800139f0>] (handle_IPI+0x144/0x158) [<800139f0>] (handle_IPI) from [<80008598>] (gic_handle_irq+0x58/0x5c) [<80008598>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0xd80b1f50 to 0xd80b1f98) 1f40: d80b1f98 3b9aca00 256aed09 0000000d 1f60: 80dbe1c8 80dbe1c8 ee7360d0 00000000 25477984 0000000d d80b0000 00000000 1f80: 00000017 d80b1f98 00000009 8049c19c 00070013 ffffffff [<80012240>] (__irq_svc) from [<8049c19c>] (cpuidle_enter_state+0x54/0xe4) [<8049c19c>] (cpuidle_enter_state) from [<8049c2e0>] (cpuidle_idle_call+0xb4/0x14c) [<8049c2e0>] (cpuidle_idle_call) from [<8000f07c>] (arch_cpu_idle+0x8/0x44) [<8000f07c>] (arch_cpu_idle) from [<8006876c>] (cpu_startup_entry+0x100/0x14c) [<8006876c>] (cpu_startup_entry) from [<10008624>] (0x10008624) CPU1: stopping Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Li Jun <jun.li@freescale.com> (cherry picked from commit 402f2d38e22007e931dc3dd52a69c0fed88452bf)
2015-07-01 19:41:03 -06:00
if (ci->role == CI_ROLE_HOST && ci->hcd) {
disable_irq_nosync(ci->irq);
host_stop(ci);
MLK-11183-1 usb: chipidea: host: fix NULL pointer problem for fast load/unload module The interrupt may occur (due to remove process may block interrupt) after we remove hcd, in that case, we should not call hcd's interrupt handler, otherwise, below NULL pointer dereference will occur, the reason for this is we call free_irq later than hcd's. So after hcd has been removed, we should not call hcd interrupt handler. ci_hdrc ci_hdrc.0: remove, state 1 usb usb1: USB disconnect, device number 1 ci_hdrc ci_hdrc.0: USB bus 1 deregistered [<800691e8>] (handle_irq_event) from [<8006c02c>] (handle_fasteoi_irq+0x84/0x14c) [<8006c02c>] (handle_fasteoi_irq) from [<800687f4>] (generic_handle_irq+0x2c/0x3c) [<800687f4>] (generic_handle_irq) from [<8000ed4c>] (handle_IRQ+0x40/0x90) [<8000ed4c>] (handle_IRQ) from [<8000856c>] (gic_handle_irq+0x2c/0x5c) [<8000856c>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0x80db1f18 to 0x80db1f60) 1f00: 80db1f60 3b9aca00 1f20: 06f86934 0000000d 80dbe1c8 80dbe1c8 ee71e0d0 00000000 06f5bb01 0000000d 1f40: 80db0000 00000000 00000017 80db1f60 00000009 8049c19c 000d0013 ffffffff [<80012240>] (__irq_svc) from [<8049c19c>] (cpuidle_enter_state+0x54/0xe4) [<8049c19c>] (cpuidle_enter_state) from [<8049c2e0>] (cpuidle_idle_call+0xb4/0x14c) [<8049c2e0>] (cpuidle_idle_call) from [<8000f07c>] (arch_cpu_idle+0x8/0x44) [<8000f07c>] (arch_cpu_idle) from [<8006876c>] (cpu_startup_entry+0x100/0x14c) [<8006876c>] (cpu_startup_entry) from [<80d52b10>] (start_kernel+0x350/0x35c) --[ end trace 1160f590a7b228b3 ]-- Unable to handle kernel NULL pointer dereference at virtual address 000000b0 pgd = 80004000 [000000b0] *pgd=00000000 Internal error: Oops: 17 1 PREEMPT SMP ARM Modules linked in: ci_hdrc_imx usbmisc_imx ci_hdrc udc_core ehci_hcd phy_mxs_usb mxc_v4l2_capture ipu_bg_overlay_sdc ipu_still ipu_prp_enc adv7180_tvin ipu_csi_enc v4l2_int_device ipu_fg_overlay_sdc mxc_mlb mxc_dcic evbug [last unloaded: phy_mxs_usb] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.14.38-usb-host-otg-02047-ga4dec77 #13 task: 80dbbae8 ti: 80db0000 task.ti: 80db0000 PC is at usb_hcd_irq+0x4/0x38 LR is at handle_irq_event_percpu+0x50/0x180 pc : [<8040eed8>] lr : [<8006907c>] psr: a00d0193 sp : 80db1e98 ip : fffffffa fp : 00000000 r10: 80e1f13f r9 : d8009900 r8 : 0000004b r7 : 00000000 r6 : 00000000 r5 : d800995c r4 : d8f2dec0 r3 : d2234010 r2 : d2234010 r1 : 00000000 r0 : 0000004b Flags: NzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 6920004a DAC: 00000015 Process swapper/0 (pid: 0, stack limit = 0x80db0238) Stack: (0x80db1e98 to 0x80db2000) 1e80: d2234010 8006907c 1ea0: 0000004b ee71da00 d8009900 d800995c d8f2dec0 f4a00100 06f5bb01 0000000d 1ec0: 80db0000 800691e8 d8009900 d800995c 00000000 8006c02c 8006bfa8 0000004b 1ee0: 0000004b 800687f4 80dace54 8000ed4c f4a0010c 80db8970 80db1f18 8000856c 1f00: 00000009 8049c19c 000d0013 ffffffff 80db1f4c 80012240 80db1f60 3b9aca00 1f20: 06f86934 0000000d 80dbe1c8 80dbe1c8 ee71e0d0 00000000 06f5bb01 0000000d 1f40: 80db0000 00000000 00000017 80db1f60 00000009 8049c19c 000d0013 ffffffff 1f60: 06f86934 0000000d 80dc4a54 ee71e0d0 80db8574 ee71e0d0 00000000 00000000 1f80: 00000000 80e797f8 80dbe1c8 8049c2e0 00000000 80db0000 80db8574 806fe48c 1fa0: 80db0038 80e1f13d 80e1f13d 8000f07c 00000000 8006876c ffffffff 80d52b10 1fc0: ffffffff ffffffff 80d5258c 00000000 00000000 80d9ef30 00000000 10c53c7d 1fe0: 80db84fc 80d9ef2c 80dbcb80 1000406a 412fc09a 10008074 00000000 00000000 [<8040eed8>] (usb_hcd_irq) from [<8006907c>] (handle_irq_event_percpu+0x50/0x180) [<8006907c>] (handle_irq_event_percpu) from [<800691e8>] (handle_irq_event+0x3c/0x5c) [<800691e8>] (handle_irq_event) from [<8006c02c>] (handle_fasteoi_irq+0x84/0x14c) [<8006c02c>] (handle_fasteoi_irq) from [<800687f4>] (generic_handle_irq+0x2c/0x3c) [<800687f4>] (generic_handle_irq) from [<8000ed4c>] (handle_IRQ+0x40/0x90) [<8000ed4c>] (handle_IRQ) from [<8000856c>] (gic_handle_irq+0x2c/0x5c) [<8000856c>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0x80db1f18 to 0x80db1f60) 1f00: 80db1f60 3b9aca00 1f20: 06f86934 0000000d 80dbe1c8 80dbe1c8 ee71e0d0 00000000 06f5bb01 0000000d 1f40: 80db0000 00000000 00000017 80db1f60 00000009 8049c19c 000d0013 ffffffff [<80012240>] (__irq_svc) from [<8049c19c>] (cpuidle_enter_state+0x54/0xe4) [<8049c19c>] (cpuidle_enter_state) from [<8049c2e0>] (cpuidle_idle_call+0xb4/0x14c) [<8049c2e0>] (cpuidle_idle_call) from [<8000f07c>] (arch_cpu_idle+0x8/0x44) [<8000f07c>] (arch_cpu_idle) from [<8006876c>] (cpu_startup_entry+0x100/0x14c) [<8006876c>] (cpu_startup_entry) from [<80d52b10>] (start_kernel+0x350/0x35c) Code: 11a002a0 03a00001 e12fff1e e92d4008 (e59130b0) --[ end trace 1160f590a7b228b4 ]-- Kernel panic - not syncing: Fatal exception in interrupt CPU2: stopping CPU: 2 PID: 1483 Comm: modprobe Tainted: G D W 3.14.38-usb-host-otg-02047-ga4dec77 #13 [<80014a68>] (unwind_backtrace) from [<80011758>] (show_stack+0x10/0x14) [<80011758>] (show_stack) from [<806f5fe8>] (dump_stack+0x7c/0xbc) [<806f5fe8>] (dump_stack) from [<800139f0>] (handle_IPI+0x144/0x158) [<800139f0>] (handle_IPI) from [<80008598>] (gic_handle_irq+0x58/0x5c) [<80008598>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0xd96c5dc0 to 0xd96c5e08) 5dc0: d800995c 0000004b 00000000 00072004 d8f2dec0 d8009900 d800995c 0000004b 5de0: d800995c a00f0013 00000000 010f2280 fffffffa d96c5e08 00000000 8006926c 5e00: 000f0013 ffffffff [<80012240>] (__irq_svc) from [<8006926c>] (synchronize_irq+0x18/0xa8) [<8006926c>] (synchronize_irq) from [<800696dc>] (__free_irq+0xfc/0x1c4) [<800696dc>] (__free_irq) from [<80069838>] (free_irq+0x4c/0xa4) [<80069838>] (free_irq) from [<8034b760>] (release_nodes+0x16c/0x1cc) [<8034b760>] (release_nodes) from [<803487ec>] (__device_release_driver+0x78/0xcc) [<803487ec>] (__device_release_driver) from [<8034885c>] (device_release_driver+0x1c/0x28) [<8034885c>] (device_release_driver) from [<8034827c>] (bus_remove_device+0xdc/0x108) [<8034827c>] (bus_remove_device) from [<80345788>] (device_del+0x100/0x1a4) [<80345788>] (device_del) from [<8034a218>] (platform_device_del+0x18/0x9c) [<8034a218>] (platform_device_del) from [<8034a2a8>] (platform_device_unregister+0xc/0x20) [<8034a2a8>] (platform_device_unregister) from [<7f61932c>] (ci_hdrc_remove_device+0xc/0x20 [ci_hdrc]) [<7f61932c>] (ci_hdrc_remove_device [ci_hdrc]) from [<7f631260>] (ci_hdrc_imx_remove+0x2c/0xdc [ci_hdrc_imx]) [<7f631260>] (ci_hdrc_imx_remove [ci_hdrc_imx]) from [<8034a350>] (platform_drv_remove+0x18/0x30) [<8034a350>] (platform_drv_remove) from [<803487e4>] (__device_release_driver+0x70/0xcc) [<803487e4>] (__device_release_driver) from [<80348ef4>] (driver_detach+0xac/0xb0) [<80348ef4>] (driver_detach) from [<803484e4>] (bus_remove_driver+0x4c/0xa0) [<803484e4>] (bus_remove_driver) from [<80084158>] (SyS_delete_module+0x11c/0x17c) [<80084158>] (SyS_delete_module) from [<8000e460>] (ret_fast_syscall+0x0/0x30) CPU3: stopping CPU: 3 PID: 0 Comm: swapper/3 Tainted: G D W 3.14.38-usb-host-otg-02047-ga4dec77 #13 [<80014a68>] (unwind_backtrace) from [<80011758>] (show_stack+0x10/0x14) [<80011758>] (show_stack) from [<806f5fe8>] (dump_stack+0x7c/0xbc) [<806f5fe8>] (dump_stack) from [<800139f0>] (handle_IPI+0x144/0x158) [<800139f0>] (handle_IPI) from [<80008598>] (gic_handle_irq+0x58/0x5c) [<80008598>] (gic_handle_irq) from [<80012240>] (__irq_svc+0x40/0x70) Exception stack(0xd80b1f50 to 0xd80b1f98) 1f40: d80b1f98 3b9aca00 256aed09 0000000d 1f60: 80dbe1c8 80dbe1c8 ee7360d0 00000000 25477984 0000000d d80b0000 00000000 1f80: 00000017 d80b1f98 00000009 8049c19c 00070013 ffffffff [<80012240>] (__irq_svc) from [<8049c19c>] (cpuidle_enter_state+0x54/0xe4) [<8049c19c>] (cpuidle_enter_state) from [<8049c2e0>] (cpuidle_idle_call+0xb4/0x14c) [<8049c2e0>] (cpuidle_idle_call) from [<8000f07c>] (arch_cpu_idle+0x8/0x44) [<8000f07c>] (arch_cpu_idle) from [<8006876c>] (cpu_startup_entry+0x100/0x14c) [<8006876c>] (cpu_startup_entry) from [<10008624>] (0x10008624) CPU1: stopping Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Li Jun <jun.li@freescale.com> (cherry picked from commit 402f2d38e22007e931dc3dd52a69c0fed88452bf)
2015-07-01 19:41:03 -06:00
enable_irq(ci->irq);
}
}
/* The below code is based on tegra ehci driver */
static int ci_ehci_hub_control(
struct usb_hcd *hcd,
u16 typeReq,
u16 wValue,
u16 wIndex,
char *buf,
u16 wLength
)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
u32 __iomem *status_reg;
u32 temp, suspend_line_state;
unsigned long flags;
int retval = 0;
struct device *dev = hcd->self.controller;
struct ci_hdrc *ci = dev_get_drvdata(dev);
status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
spin_lock_irqsave(&ehci->lock, flags);
if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
temp = ehci_readl(ehci, status_reg);
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
retval = -EPIPE;
goto done;
}
temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E);
temp |= PORT_WKDISC_E | PORT_WKOC_E;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
/*
* If a transaction is in progress, there may be a delay in
* suspending the port. Poll until the port is suspended.
*/
if (ehci_handshake(ehci, status_reg, PORT_SUSPEND,
PORT_SUSPEND, 5000))
ehci_err(ehci, "timeout waiting for SUSPEND\n");
if (ci->platdata->flags & CI_HDRC_HOST_SUSP_PHY_LPM) {
if (PORT_SPEED_LOW(temp))
suspend_line_state = PORTSC_LS_K;
else
suspend_line_state = PORTSC_LS_J;
if (!ehci_handshake(ehci, status_reg, PORTSC_LS,
suspend_line_state, 5000))
ci_hdrc_enter_lpm(ci, true);
}
if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) {
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
CI_HDRC_IMX_HSIC_SUSPEND_EVENT);
temp = ehci_readl(ehci, status_reg);
temp &= ~(PORT_WKDISC_E | PORT_WKCONN_E);
ehci_writel(ehci, temp, status_reg);
}
spin_unlock_irqrestore(&ehci->lock, flags);
if (ehci_port_speed(ehci, temp) ==
USB_PORT_STAT_HIGH_SPEED && hcd->usb_phy) {
/* notify the USB PHY */
usb_phy_notify_suspend(hcd->usb_phy, USB_SPEED_HIGH);
}
spin_lock_irqsave(&ehci->lock, flags);
set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
goto done;
}
/*
* After resume has finished, it needs do some post resume
* operation for some SoCs.
*/
else if (typeReq == ClearPortFeature &&
wValue == USB_PORT_FEAT_C_SUSPEND) {
/* Make sure the resume has finished, it should be finished */
if (ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 25000))
ehci_err(ehci, "timeout waiting for resume\n");
temp = ehci_readl(ehci, status_reg);
if (ehci_port_speed(ehci, temp) ==
USB_PORT_STAT_HIGH_SPEED && hcd->usb_phy) {
/* notify the USB PHY */
usb_phy_notify_resume(hcd->usb_phy, USB_SPEED_HIGH);
}
}
spin_unlock_irqrestore(&ehci->lock, flags);
/* Handle the hub control events here */
return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
done:
spin_unlock_irqrestore(&ehci->lock, flags);
return retval;
}
usb: chipidea: host: add .bus_suspend quirk For chipidea, its resume sequence is not-EHCI compatible, see below description for FPR at portsc. So in order to send SoF in time for remote wakeup sequence(within 3ms), the RUN/STOP bit must be set before the resume signal is ended, but the usb resume code may run after resume signal is ended, so we had to set it at suspend path. Force Port Resume - RW. Default = 0b. 1= Resume detected/driven on port. 0=No resume (K-state) detected/driven on port. Host mode: Software sets this bit to one to drive resume signaling. The Controller sets this bit to '1' if a J-to-K transition is detected while the port is in the Suspend state. When this bit transitions to a '1' because a J-to-K transition is detected, the Port Change Detect bit in the USBSTS register is also set to '1'. This bit will automatically change to '0' after the resume sequence is complete. This behavior is different from EHCI where the controller driver is required to set this bit to a '0' after the resume duration is timed in the driver. Note that when the controller owns the port, the resume sequence follows the defined sequence documented in the USB Specification Revision 2.0. The resume signaling (Full-speed 'K') is driven on the port as long as this bit remains a '1'. This bit will remain a '1' until the port has switched to idle. Writing a '0' has no affect because the port controller will time the resume operation, clear the bit and the port control state switches to HS or FS idle. This field is '0' if Port Power(PP) is '0' in host mode. This bit is not-EHCI compatible. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-02-10 21:44:59 -07:00
static int ci_ehci_bus_suspend(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct device *dev = hcd->self.controller;
struct ci_hdrc *ci = dev_get_drvdata(dev);
usb: chipidea: host: add .bus_suspend quirk For chipidea, its resume sequence is not-EHCI compatible, see below description for FPR at portsc. So in order to send SoF in time for remote wakeup sequence(within 3ms), the RUN/STOP bit must be set before the resume signal is ended, but the usb resume code may run after resume signal is ended, so we had to set it at suspend path. Force Port Resume - RW. Default = 0b. 1= Resume detected/driven on port. 0=No resume (K-state) detected/driven on port. Host mode: Software sets this bit to one to drive resume signaling. The Controller sets this bit to '1' if a J-to-K transition is detected while the port is in the Suspend state. When this bit transitions to a '1' because a J-to-K transition is detected, the Port Change Detect bit in the USBSTS register is also set to '1'. This bit will automatically change to '0' after the resume sequence is complete. This behavior is different from EHCI where the controller driver is required to set this bit to a '0' after the resume duration is timed in the driver. Note that when the controller owns the port, the resume sequence follows the defined sequence documented in the USB Specification Revision 2.0. The resume signaling (Full-speed 'K') is driven on the port as long as this bit remains a '1'. This bit will remain a '1' until the port has switched to idle. Writing a '0' has no affect because the port controller will time the resume operation, clear the bit and the port control state switches to HS or FS idle. This field is '0' if Port Power(PP) is '0' in host mode. This bit is not-EHCI compatible. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-02-10 21:44:59 -07:00
int port;
u32 tmp;
int ret = orig_bus_suspend(hcd);
if (ret)
return ret;
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status[port];
u32 portsc = ehci_readl(ehci, reg);
if (portsc & PORT_CONNECT) {
/*
* For chipidea, the resume signal will be ended
* automatically, so for remote wakeup case, the
* usbcmd.rs may not be set before the resume has
* ended if other resume paths consumes too much
* time (~24ms), in that case, the SOF will not
* send out within 3ms after resume ends, then the
* high speed device will enter full speed mode.
*/
tmp = ehci_readl(ehci, &ehci->regs->command);
tmp |= CMD_RUN;
ehci_writel(ehci, tmp, &ehci->regs->command);
/*
* It needs a short delay between set RS bit and PHCD.
*/
usleep_range(150, 200);
/*
* If a transaction is in progress, there may be
* a delay in suspending the port. Poll until the
* port is suspended.
*/
if (test_bit(port, &ehci->bus_suspended) &&
ehci_handshake(ehci, reg, PORT_SUSPEND,
PORT_SUSPEND, 5000))
ehci_err(ehci, "timeout waiting for SUSPEND\n");
/*
* Need to clear WKCN and WKOC for imx HSIC,
* otherwise, there will be wakeup event.
*/
if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) {
tmp = ehci_readl(ehci, reg);
tmp &= ~(PORT_WKDISC_E | PORT_WKCONN_E);
ehci_writel(ehci, tmp, reg);
}
if (hcd->usb_phy && test_bit(port, &ehci->bus_suspended)
&& (ehci_port_speed(ehci, portsc) ==
USB_PORT_STAT_HIGH_SPEED))
/*
* notify the USB PHY, it is for global
* suspend case.
*/
usb_phy_notify_suspend(hcd->usb_phy,
USB_SPEED_HIGH);
usb: chipidea: host: add .bus_suspend quirk For chipidea, its resume sequence is not-EHCI compatible, see below description for FPR at portsc. So in order to send SoF in time for remote wakeup sequence(within 3ms), the RUN/STOP bit must be set before the resume signal is ended, but the usb resume code may run after resume signal is ended, so we had to set it at suspend path. Force Port Resume - RW. Default = 0b. 1= Resume detected/driven on port. 0=No resume (K-state) detected/driven on port. Host mode: Software sets this bit to one to drive resume signaling. The Controller sets this bit to '1' if a J-to-K transition is detected while the port is in the Suspend state. When this bit transitions to a '1' because a J-to-K transition is detected, the Port Change Detect bit in the USBSTS register is also set to '1'. This bit will automatically change to '0' after the resume sequence is complete. This behavior is different from EHCI where the controller driver is required to set this bit to a '0' after the resume duration is timed in the driver. Note that when the controller owns the port, the resume sequence follows the defined sequence documented in the USB Specification Revision 2.0. The resume signaling (Full-speed 'K') is driven on the port as long as this bit remains a '1'. This bit will remain a '1' until the port has switched to idle. Writing a '0' has no affect because the port controller will time the resume operation, clear the bit and the port control state switches to HS or FS idle. This field is '0' if Port Power(PP) is '0' in host mode. This bit is not-EHCI compatible. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-02-10 21:44:59 -07:00
break;
}
}
return 0;
}
static int ci_ehci_bus_resume(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int port;
int ret = orig_bus_resume(hcd);
if (ret)
return ret;
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status[port];
u32 portsc = ehci_readl(ehci, reg);
/*
* Notify PHY after resume signal has finished, it is
* for global suspend case.
*/
if (hcd->usb_phy
&& test_bit(port, &ehci->bus_suspended)
&& (portsc & PORT_CONNECT)
&& (ehci_port_speed(ehci, portsc) ==
USB_PORT_STAT_HIGH_SPEED))
/* notify the USB PHY */
usb_phy_notify_resume(hcd->usb_phy, USB_SPEED_HIGH);
}
return 0;
}
int ci_hdrc_host_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_HC))
return -ENXIO;
rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
if (!rdrv)
return -ENOMEM;
rdrv->start = host_start;
rdrv->stop = host_stop;
rdrv->irq = host_irq;
rdrv->suspend = ci_hdrc_host_suspend;
rdrv->resume = ci_hdrc_host_resume;
rdrv->name = "host";
ci->roles[CI_ROLE_HOST] = rdrv;
usb: chipidea: ehci_init_driver is intended to call one time The ehci_init_driver is used to initialize hcd APIs for each ehci controller driver, it is designed to be called only one time and before driver register is called. The current design will cause ehci_init_driver is called multiple times at probe process, it will cause hc_driver's initialization affect current running hcd. We run out NULL pointer dereference problem when one hcd is started by module_init, and the other is started by otg thread at SMP platform. The reason for this problem is ehci_init_driver will do memory copy for current uniform hc_driver, and this memory copy will do memset (as 0) first, so when the first hcd is running usb_add_hcd, and the second hcd may clear the uniform hc_driver's space (at ehci_init_driver), then the first hcd will meet NULL pointer at the same time. See below two logs: LOG_1: ci_hdrc ci_hdrc.0: EHCI Host Controller ci_hdrc ci_hdrc.0: new USB bus registered, assigned bus number 1 ci_hdrc ci_hdrc.1: doesn't support gadget Unable to handle kernel NULL pointer dereference at virtual address 00000014 pgd = 80004000 [00000014] *pgd=00000000 Internal error: Oops: 805 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 108 Comm: kworker/u8:2 Not tainted 3.14.38-222193-g24b2734-dirty #25 Workqueue: ci_otg ci_otg_work task: d839ec00 ti: d8400000 task.ti: d8400000 PC is at ehci_run+0x4c/0x284 LR is at _raw_spin_unlock_irqrestore+0x28/0x54 pc : [<8041f9a0>] lr : [<8070ea84>] psr: 60000113 sp : d8401e30 ip : 00000000 fp : d8004400 r10: 00000001 r9 : 00000001 r8 : 00000000 r7 : 00000000 r6 : d8419940 r5 : 80dd24c0 r4 : d8419800 r3 : 8001d060 r2 : 00000000 r1 : 00000001 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 1000404a DAC: 00000015 Process kworker/u8:2 (pid: 108, stack limit = 0xd8400238) Stack: (0xd8401e30 to 0xd8402000) 1e20: d87523c0 d8401e48 66667562 d8419800 1e40: 00000000 00000000 d8419800 00000000 00000000 00000000 d84198b0 8040fcdc 1e60: 00000000 80dd320c d8477610 d8419c00 d803d010 d8419800 00000000 00000000 1e80: d8004400 00000000 d8400008 80431494 80431374 d803d100 d803d010 d803d1ac 1ea0: 00000000 80432428 804323d4 d803d100 00000001 80435eb8 80e0d0bc d803d100 1ec0: 00000006 80436458 00000000 d803d100 80e92ec8 80436f44 d803d010 d803d100 1ee0: d83fde00 8043292c d8752710 d803d1f4 d803d010 8042ddfc 8042ddb8 d83f3b00 1f00: d803d1f4 80042b60 00000000 00000003 00000001 00000001 80054598 d83f3b00 1f20: d8004400 d83f3b18 d8004414 d8400000 80e3957b 00000089 d8004400 80043814 1f40: d839ec00 00000000 d83fcd80 d83f3b00 800436e4 00000000 00000000 00000000 1f60: 00000000 80048f34 00000000 00000000 00000000 d83f3b00 00000000 00000000 1f80: d8401f80 d8401f80 00000000 00000000 d8401f90 d8401f90 d8401fac d83fcd80 1fa0: 80048e68 00000000 00000000 8000e538 00000000 00000000 00000000 00000000 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000 [<8041f9a0>] (ehci_run) from [<8040fcdc>] (usb_add_hcd+0x248/0x6e8) [<8040fcdc>] (usb_add_hcd) from [<80431494>] (host_start+0x120/0x2e4) [<80431494>] (host_start) from [<80432428>] (ci_otg_start_host+0x54/0xbc) [<80432428>] (ci_otg_start_host) from [<80435eb8>] (otg_set_protocol+0xa4/0xd0) [<80435eb8>] (otg_set_protocol) from [<80436458>] (otg_set_state+0x574/0xc58) [<80436458>] (otg_set_state) from [<80436f44>] (otg_statemachine+0x408/0x46c) [<80436f44>] (otg_statemachine) from [<8043292c>] (ci_otg_fsm_work+0x3c/0x190) [<8043292c>] (ci_otg_fsm_work) from [<8042ddfc>] (ci_otg_work+0x44/0x1c4) [<8042ddfc>] (ci_otg_work) from [<80042b60>] (process_one_work+0xf4/0x35c) [<80042b60>] (process_one_work) from [<80043814>] (worker_thread+0x130/0x3bc) [<80043814>] (worker_thread) from [<80048f34>] (kthread+0xcc/0xe4) [<80048f34>] (kthread) from [<8000e538>] (ret_from_fork+0x14/0x3c) Code: e5953018 e3530000 0a000000 e12fff33 (e5878014) LOG_2: ci_hdrc ci_hdrc.0: EHCI Host Controller ci_hdrc ci_hdrc.0: new USB bus registered, assigned bus number 1 ci_hdrc ci_hdrc.1: doesn't support gadget Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = 80004000 [00000000] *pgd=00000000 In Online 00:00ternal e Offline rror: Oops: 80000005 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 108 Comm: kworker/u8:2 Not tainted 3.14.38-02007-g24b2734-dirty #127 Workque Online 00:00ue: ci_o Offline tg ci_otg_work Online 00:00task: d8 Offline 39ec00 ti: d83ea000 task.ti: d83ea000 PC is at 0x0 LR is at usb_add_hcd+0x248/0x6e8 pc : [<00000000>] lr : [<8040f644>] psr: 60000113 sp : d83ebe60 ip : 00000000 fp : d8004400 r10: 00000001 r9 : 00000001 r8 : d85fd4b0 r7 : 00000000 r6 : 00000000 r5 : 00000000 r4 : d85fd400 r3 : 00000000 r2 : d85fd4f4 r1 : 80410178 r0 : d85fd400 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 1000404a DAC: 00000015 Process kworker/u8:2 (pid: 108, stack limit = 0xd83ea238) Stack: (0xd83ebe60 to 0xd83ec000) be60: 00000000 80dd920c d8654e10 d85fd800 d803e010 d85fd400 00000000 00000000 be80: d8004400 00000000 d83ea008 80430e34 80430d14 d803e100 d803e010 d803e1ac bea0: 00000000 80431dc8 80431d74 d803e100 00000001 80435858 80e130bc d803e100 bec0: 00000006 80435df8 00000000 d803e100 80e98ec8 804368e4 d803e010 d803e100 bee0: d86e8100 804322cc d86cf050 d803e1f4 d803e010 8042d79c 8042d758 d83cf900 bf00: d803e1f4 80042b78 00000000 00000003 00000001 00000001 800545e8 d83cf900 bf20: d8004400 d83cf918 d8004414 d83ea000 80e3f57b 00000089 d8004400 8004382c bf40: d839ec00 00000000 d8393780 d83cf900 800436fc 00000000 00000000 00000000 bf60: 00000000 80048f50 80e019f4 00000000 0000264c d83cf900 00000000 00000000 bf80: d83ebf80 d83ebf80 00000000 00000000 d83ebf90 d83ebf90 d83ebfac d8393780 bfa0: 80048e84 00000000 00000000 8000e538 00000000 00000000 00000000 00000000 bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 ee66e85d 133ebd03 [<804 Online 00:000f644>] Offline (usb_add_hcd) from [<80430e34>] (host_start+0x120/0x2e4) [<80430e34>] (host_start) from [<80431dc8>] (ci_otg_start_host+0x54/0xbc) [<80431dc8>] (ci_otg_start_host) from [<80435858>] (otg_set_protocol+0xa4/0xd0) [<80435858>] (otg_set_protocol) from [<80435df8>] (otg_set_state+0x574/0xc58) [<80435df8>] (otg_set_state) from [<804368e4>] (otg_statemachine+0x408/0x46c) [<804368e4>] (otg_statemachine) from [<804322cc>] (ci_otg_fsm_work+0x3c/0x190) [<804322cc>] (ci_otg_fsm_work) from [<8042d79c>] (ci_otg_work+0x44/0x1c4) [<8042d79c>] (ci_otg_work) from [<80042b78>] (process_one_work+0xf4/0x35c) [<80042b78>] (process_one_work) from [<8004382c>] (worker_thread+0x130/0x3bc) [<8004382c>] (worker_thread) from [<80048f50>] (kthread+0xcc/0xe4) [<80048f50>] (kthread) from [<8000e538>] (ret_from_fork+0x14/0x3c) Code: bad PC value Cc: Jun Li <jun.li@freescale.com> Cc: <stable@vger.kernel.org> Cc: Alan Stern <stern@rowland.harvard.edu> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Peter Chen <peter.chen@freescale.com>
2015-07-20 19:51:29 -06:00
return 0;
}
void ci_hdrc_host_driver_init(void)
{
ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
usb: chipidea: host: add .bus_suspend quirk For chipidea, its resume sequence is not-EHCI compatible, see below description for FPR at portsc. So in order to send SoF in time for remote wakeup sequence(within 3ms), the RUN/STOP bit must be set before the resume signal is ended, but the usb resume code may run after resume signal is ended, so we had to set it at suspend path. Force Port Resume - RW. Default = 0b. 1= Resume detected/driven on port. 0=No resume (K-state) detected/driven on port. Host mode: Software sets this bit to one to drive resume signaling. The Controller sets this bit to '1' if a J-to-K transition is detected while the port is in the Suspend state. When this bit transitions to a '1' because a J-to-K transition is detected, the Port Change Detect bit in the USBSTS register is also set to '1'. This bit will automatically change to '0' after the resume sequence is complete. This behavior is different from EHCI where the controller driver is required to set this bit to a '0' after the resume duration is timed in the driver. Note that when the controller owns the port, the resume sequence follows the defined sequence documented in the USB Specification Revision 2.0. The resume signaling (Full-speed 'K') is driven on the port as long as this bit remains a '1'. This bit will remain a '1' until the port has switched to idle. Writing a '0' has no affect because the port controller will time the resume operation, clear the bit and the port control state switches to HS or FS idle. This field is '0' if Port Power(PP) is '0' in host mode. This bit is not-EHCI compatible. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-02-10 21:44:59 -07:00
orig_bus_suspend = ci_ehci_hc_driver.bus_suspend;
orig_bus_resume = ci_ehci_hc_driver.bus_resume;
ci_ehci_hc_driver.bus_resume = ci_ehci_bus_resume;
usb: chipidea: host: add .bus_suspend quirk For chipidea, its resume sequence is not-EHCI compatible, see below description for FPR at portsc. So in order to send SoF in time for remote wakeup sequence(within 3ms), the RUN/STOP bit must be set before the resume signal is ended, but the usb resume code may run after resume signal is ended, so we had to set it at suspend path. Force Port Resume - RW. Default = 0b. 1= Resume detected/driven on port. 0=No resume (K-state) detected/driven on port. Host mode: Software sets this bit to one to drive resume signaling. The Controller sets this bit to '1' if a J-to-K transition is detected while the port is in the Suspend state. When this bit transitions to a '1' because a J-to-K transition is detected, the Port Change Detect bit in the USBSTS register is also set to '1'. This bit will automatically change to '0' after the resume sequence is complete. This behavior is different from EHCI where the controller driver is required to set this bit to a '0' after the resume duration is timed in the driver. Note that when the controller owns the port, the resume sequence follows the defined sequence documented in the USB Specification Revision 2.0. The resume signaling (Full-speed 'K') is driven on the port as long as this bit remains a '1'. This bit will remain a '1' until the port has switched to idle. Writing a '0' has no affect because the port controller will time the resume operation, clear the bit and the port control state switches to HS or FS idle. This field is '0' if Port Power(PP) is '0' in host mode. This bit is not-EHCI compatible. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-02-10 21:44:59 -07:00
ci_ehci_hc_driver.bus_suspend = ci_ehci_bus_suspend;
ci_ehci_hc_driver.hub_control = ci_ehci_hub_control;
}