Loading drivers/platform/msm/usb_bam.c +127 −5 Original line number Diff line number Diff line Loading @@ -2729,12 +2729,12 @@ int usb_bam_disconnect_pipe(enum usb_ctrl bam_type, u8 idx) if (bam_type == CI_CTRL) msm_hw_bam_disable(0); } /* Enable usb irq here which is disabled in function drivers * during disconnect after BAM reset. */ if (bam_type == CI_CTRL) if (!ctx->pipes_enabled_per_bam && (bam_type == CI_CTRL)) msm_usb_irq_disable(false); } /* This function is directly called by USB Transport drivers * to disconnect pipes. Drop runtime usage count here. For * IPA, caller takes care of it Loading Loading @@ -3136,6 +3136,7 @@ static int usb_bam_init(struct platform_device *pdev) && bam_type == CI_CTRL) { pr_debug("Register and enable HSUSB BAM\n"); props.options |= SPS_BAM_OPT_ENABLE_AT_BOOT; props.options |= SPS_BAM_FORCE_RESET; } dev = &ctx->usb_bam_pdev->dev; Loading Loading @@ -3406,6 +3407,127 @@ int usb_bam_get_bam_type(const char *core_name) } EXPORT_SYMBOL(usb_bam_get_bam_type); /* * This function makes sure ipa endpoints are disabled for both USB->IPA * and IPA->USB pipes before USB bam reset. USB BAM reset is required to * to avoid EP flush issues while disabling USB endpoints on disconnect. */ int msm_do_bam_disable_enable(enum usb_ctrl bam) { struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam]; struct sps_pipe *pipe; u32 timeout = 10, pipe_empty; int ret = 0, i; struct sps_connect *sps_connection; struct usb_bam_sps_type usb_bam_sps = ctx->usb_bam_sps; struct usb_bam_pipe_connect *pipe_connect; int qdss_idx; struct msm_usb_bam_data *usb_bam_data; if (!ctx->usb_bam_pdev) return 0; usb_bam_data = ctx->usb_bam_data; if ((bam != CI_CTRL) || !usb_bam_data->enable_hsusb_bam_on_boot) return 0; if (!ctx->pipes_enabled_per_bam || info[bam].pipes_suspended) return 0; if (in_interrupt()) { pr_err("%s:API called in interrupt context\n", __func__); return 0; } mutex_lock(&info[bam].suspend_resume_mutex); log_event_dbg("%s: Perform USB BAM reset\n", __func__); /* Get QDSS pipe index to avoid pipe reset */ qdss_idx = usb_bam_get_connection_idx(qdss_usb_bam_type, QDSS_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); for (i = 0; i < ctx->max_connections; i++) { pipe_connect = &ctx->usb_bam_connections[i]; if (pipe_connect->enabled && (pipe_connect->dir == PEER_PERIPHERAL_TO_USB) && (qdss_idx != i)) { /* Call to disable IPA producer endpoint */ ipa_disable_endpoint(pipe_connect->ipa_clnt_hdl); sps_pipe_reset(ctx->h_bam, pipe_connect->dst_pipe_index); } } for (i = 0; i < ctx->max_connections; i++) { pipe_connect = &ctx->usb_bam_connections[i]; if (pipe_connect->enabled && (pipe_connect->dir == USB_TO_PEER_PERIPHERAL) && (qdss_idx != i)) { pipe = ctx->usb_bam_sps.sps_pipes[i]; sps_connection = &usb_bam_sps.sps_connections[i]; timeout = 10; /* * On some platforms, there is a chance that flow * control is disabled from IPA side, due to this IPA * core may not consume data from USB. Hence notify IPA * to enable flow control and then check sps pipe is * empty or not before processing USB->IPA disconnect. */ ipa_clear_endpoint_delay(pipe_connect->ipa_clnt_hdl); /* Make sure pipes are empty before disconnecting it */ while (1) { ret = sps_is_pipe_empty(pipe, &pipe_empty); if (ret) { log_event_err("%s: pipeempty fail %d\n", __func__, ret); goto err; } if (pipe_empty || !--timeout) break; /* Check again */ usleep_range(1000, 2000); } if (!pipe_empty) { log_event_dbg("%s: Inject ZLT\n", __func__); sps_pipe_inject_zlt(sps_connection->destination, sps_connection->dest_pipe_index); timeout = 0; while (1) { ret = sps_is_pipe_empty(pipe, &pipe_empty); if (ret) goto err; if (pipe_empty) break; timeout++; /* Check again */ usleep_range(1000, 2000); } } /* Call to disable IPA consumer endpoint */ ipa_disable_endpoint(pipe_connect->ipa_clnt_hdl); sps_pipe_reset(ctx->h_bam, pipe_connect->src_pipe_index); } } /* Perform USB BAM reset */ msm_hw_bam_disable(1); sps_device_reset(ctx->h_bam); msm_hw_bam_disable(0); log_event_dbg("%s: USB BAM reset done\n", __func__); ret = 0; err: mutex_unlock(&info[bam].suspend_resume_mutex); return ret; } EXPORT_SYMBOL(msm_do_bam_disable_enable); bool msm_usb_bam_enable(enum usb_ctrl bam, bool bam_enable) { struct msm_usb_bam_data *usb_bam_data; Loading drivers/usb/gadget/composite.c +20 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/usb/composite.h> #include <linux/usb/otg.h> #include <linux/usb/msm_hsusb.h> #include <asm/unaligned.h> #include "u_os_desc.h" Loading Loading @@ -856,6 +857,11 @@ static void reset_config(struct usb_composite_dev *cdev) DBG(cdev, "reset config\n"); if (!cdev->config) { pr_err("%s:cdev->config is already NULL\n", __func__); return; } list_for_each_entry(f, &cdev->config->functions, list) { if (f->disable) f->disable(f); Loading Loading @@ -1120,8 +1126,14 @@ void usb_remove_config(struct usb_composite_dev *cdev, spin_lock_irqsave(&cdev->lock, flags); if (cdev->config == config) if (cdev->config == config) { if (cdev->gadget->is_chipidea && !cdev->suspended) { spin_unlock_irqrestore(&cdev->lock, flags); msm_do_bam_disable_enable(CI_CTRL); spin_lock_irqsave(&cdev->lock, flags); } reset_config(cdev); } spin_unlock_irqrestore(&cdev->lock, flags); Loading Loading @@ -2161,8 +2173,14 @@ void composite_disconnect(struct usb_gadget *gadget) * disconnect callbacks? */ spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) if (cdev->config) { if (gadget->is_chipidea && !cdev->suspended) { spin_unlock_irqrestore(&cdev->lock, flags); msm_do_bam_disable_enable(CI_CTRL); spin_lock_irqsave(&cdev->lock, flags); } reset_config(cdev); } if (cdev->driver->disconnect) cdev->driver->disconnect(cdev); if (cdev->delayed_status != 0) { Loading drivers/usb/gadget/function/u_qdss.c +30 −8 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -20,6 +20,7 @@ static int alloc_sps_req(struct usb_ep *data_ep) { struct usb_request *req = NULL; struct f_qdss *qdss = data_ep->driver_data; struct usb_gadget *gadget = qdss->gadget; u32 sps_params = 0; pr_debug("send_sps_req\n"); Loading @@ -30,9 +31,17 @@ static int alloc_sps_req(struct usb_ep *data_ep) return -ENOMEM; } if (!gadget->is_chipidea) { req->length = 32*1024; sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | qdss->bam_info.usb_bam_pipe_idx; } else { /* non DWC3 BAM requires req->length to be 0 */ req->length = 0; sps_params = (MSM_SPS_MODE | qdss->bam_info.usb_bam_pipe_idx | MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER; } req->udc_priv = sps_params; qdss->endless_req = req; Loading Loading @@ -107,10 +116,12 @@ int set_qdss_data_connection(struct f_qdss *qdss, int enable) NULL, bam_info.data_fifo, NULL); alloc_sps_req(qdss->port.data); if (!gadget->is_chipidea) msm_data_fifo_config(qdss->port.data, bam_info.data_fifo->iova, bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx); init_data(qdss->port.data); res = usb_bam_connect(usb_bam_type, idx, Loading @@ -132,8 +143,14 @@ int set_qdss_data_connection(struct f_qdss *qdss, int enable) static int init_data(struct usb_ep *ep) { struct f_qdss *qdss = ep->driver_data; struct usb_gadget *gadget = qdss->gadget; int res = 0; if (gadget->is_chipidea) { pr_debug("QDSS is used with non DWC3 core\n"); return res; } pr_debug("init_data\n"); res = msm_ep_config(ep, qdss->endless_req); Loading @@ -145,8 +162,13 @@ static int init_data(struct usb_ep *ep) int uninit_data(struct usb_ep *ep) { struct f_qdss *qdss = ep->driver_data; struct usb_gadget *gadget = qdss->gadget; int res = 0; if (gadget->is_chipidea) return res; pr_err("uninit_data\n"); res = msm_ep_unconfig(ep); Loading include/linux/usb_bam.h +2 −0 Original line number Diff line number Diff line Loading @@ -438,6 +438,7 @@ int get_qdss_bam_info(enum usb_ctrl cur_bam, u8 idx, bool msm_bam_hsic_lpm_ok(void); bool msm_bam_hsic_host_pipe_empty(void); bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable); int msm_do_bam_disable_enable(enum usb_ctrl ctrl); #else static inline int usb_bam_connect(enum usb_ctrl bam, u8 idx, u32 *bam_pipe_idx, unsigned long iova) Loading Loading @@ -543,6 +544,7 @@ static inline bool msm_bam_hsic_lpm_ok(void) { return true; } static inline bool msm_bam_hsic_host_pipe_empty(void) { return true; } static inline bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable) { return true; } int msm_do_bam_disable_enable(enum usb_ctrl ctrl) { return true; } #endif Loading Loading
drivers/platform/msm/usb_bam.c +127 −5 Original line number Diff line number Diff line Loading @@ -2729,12 +2729,12 @@ int usb_bam_disconnect_pipe(enum usb_ctrl bam_type, u8 idx) if (bam_type == CI_CTRL) msm_hw_bam_disable(0); } /* Enable usb irq here which is disabled in function drivers * during disconnect after BAM reset. */ if (bam_type == CI_CTRL) if (!ctx->pipes_enabled_per_bam && (bam_type == CI_CTRL)) msm_usb_irq_disable(false); } /* This function is directly called by USB Transport drivers * to disconnect pipes. Drop runtime usage count here. For * IPA, caller takes care of it Loading Loading @@ -3136,6 +3136,7 @@ static int usb_bam_init(struct platform_device *pdev) && bam_type == CI_CTRL) { pr_debug("Register and enable HSUSB BAM\n"); props.options |= SPS_BAM_OPT_ENABLE_AT_BOOT; props.options |= SPS_BAM_FORCE_RESET; } dev = &ctx->usb_bam_pdev->dev; Loading Loading @@ -3406,6 +3407,127 @@ int usb_bam_get_bam_type(const char *core_name) } EXPORT_SYMBOL(usb_bam_get_bam_type); /* * This function makes sure ipa endpoints are disabled for both USB->IPA * and IPA->USB pipes before USB bam reset. USB BAM reset is required to * to avoid EP flush issues while disabling USB endpoints on disconnect. */ int msm_do_bam_disable_enable(enum usb_ctrl bam) { struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam]; struct sps_pipe *pipe; u32 timeout = 10, pipe_empty; int ret = 0, i; struct sps_connect *sps_connection; struct usb_bam_sps_type usb_bam_sps = ctx->usb_bam_sps; struct usb_bam_pipe_connect *pipe_connect; int qdss_idx; struct msm_usb_bam_data *usb_bam_data; if (!ctx->usb_bam_pdev) return 0; usb_bam_data = ctx->usb_bam_data; if ((bam != CI_CTRL) || !usb_bam_data->enable_hsusb_bam_on_boot) return 0; if (!ctx->pipes_enabled_per_bam || info[bam].pipes_suspended) return 0; if (in_interrupt()) { pr_err("%s:API called in interrupt context\n", __func__); return 0; } mutex_lock(&info[bam].suspend_resume_mutex); log_event_dbg("%s: Perform USB BAM reset\n", __func__); /* Get QDSS pipe index to avoid pipe reset */ qdss_idx = usb_bam_get_connection_idx(qdss_usb_bam_type, QDSS_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); for (i = 0; i < ctx->max_connections; i++) { pipe_connect = &ctx->usb_bam_connections[i]; if (pipe_connect->enabled && (pipe_connect->dir == PEER_PERIPHERAL_TO_USB) && (qdss_idx != i)) { /* Call to disable IPA producer endpoint */ ipa_disable_endpoint(pipe_connect->ipa_clnt_hdl); sps_pipe_reset(ctx->h_bam, pipe_connect->dst_pipe_index); } } for (i = 0; i < ctx->max_connections; i++) { pipe_connect = &ctx->usb_bam_connections[i]; if (pipe_connect->enabled && (pipe_connect->dir == USB_TO_PEER_PERIPHERAL) && (qdss_idx != i)) { pipe = ctx->usb_bam_sps.sps_pipes[i]; sps_connection = &usb_bam_sps.sps_connections[i]; timeout = 10; /* * On some platforms, there is a chance that flow * control is disabled from IPA side, due to this IPA * core may not consume data from USB. Hence notify IPA * to enable flow control and then check sps pipe is * empty or not before processing USB->IPA disconnect. */ ipa_clear_endpoint_delay(pipe_connect->ipa_clnt_hdl); /* Make sure pipes are empty before disconnecting it */ while (1) { ret = sps_is_pipe_empty(pipe, &pipe_empty); if (ret) { log_event_err("%s: pipeempty fail %d\n", __func__, ret); goto err; } if (pipe_empty || !--timeout) break; /* Check again */ usleep_range(1000, 2000); } if (!pipe_empty) { log_event_dbg("%s: Inject ZLT\n", __func__); sps_pipe_inject_zlt(sps_connection->destination, sps_connection->dest_pipe_index); timeout = 0; while (1) { ret = sps_is_pipe_empty(pipe, &pipe_empty); if (ret) goto err; if (pipe_empty) break; timeout++; /* Check again */ usleep_range(1000, 2000); } } /* Call to disable IPA consumer endpoint */ ipa_disable_endpoint(pipe_connect->ipa_clnt_hdl); sps_pipe_reset(ctx->h_bam, pipe_connect->src_pipe_index); } } /* Perform USB BAM reset */ msm_hw_bam_disable(1); sps_device_reset(ctx->h_bam); msm_hw_bam_disable(0); log_event_dbg("%s: USB BAM reset done\n", __func__); ret = 0; err: mutex_unlock(&info[bam].suspend_resume_mutex); return ret; } EXPORT_SYMBOL(msm_do_bam_disable_enable); bool msm_usb_bam_enable(enum usb_ctrl bam, bool bam_enable) { struct msm_usb_bam_data *usb_bam_data; Loading
drivers/usb/gadget/composite.c +20 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <linux/usb/composite.h> #include <linux/usb/otg.h> #include <linux/usb/msm_hsusb.h> #include <asm/unaligned.h> #include "u_os_desc.h" Loading Loading @@ -856,6 +857,11 @@ static void reset_config(struct usb_composite_dev *cdev) DBG(cdev, "reset config\n"); if (!cdev->config) { pr_err("%s:cdev->config is already NULL\n", __func__); return; } list_for_each_entry(f, &cdev->config->functions, list) { if (f->disable) f->disable(f); Loading Loading @@ -1120,8 +1126,14 @@ void usb_remove_config(struct usb_composite_dev *cdev, spin_lock_irqsave(&cdev->lock, flags); if (cdev->config == config) if (cdev->config == config) { if (cdev->gadget->is_chipidea && !cdev->suspended) { spin_unlock_irqrestore(&cdev->lock, flags); msm_do_bam_disable_enable(CI_CTRL); spin_lock_irqsave(&cdev->lock, flags); } reset_config(cdev); } spin_unlock_irqrestore(&cdev->lock, flags); Loading Loading @@ -2161,8 +2173,14 @@ void composite_disconnect(struct usb_gadget *gadget) * disconnect callbacks? */ spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) if (cdev->config) { if (gadget->is_chipidea && !cdev->suspended) { spin_unlock_irqrestore(&cdev->lock, flags); msm_do_bam_disable_enable(CI_CTRL); spin_lock_irqsave(&cdev->lock, flags); } reset_config(cdev); } if (cdev->driver->disconnect) cdev->driver->disconnect(cdev); if (cdev->delayed_status != 0) { Loading
drivers/usb/gadget/function/u_qdss.c +30 −8 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -20,6 +20,7 @@ static int alloc_sps_req(struct usb_ep *data_ep) { struct usb_request *req = NULL; struct f_qdss *qdss = data_ep->driver_data; struct usb_gadget *gadget = qdss->gadget; u32 sps_params = 0; pr_debug("send_sps_req\n"); Loading @@ -30,9 +31,17 @@ static int alloc_sps_req(struct usb_ep *data_ep) return -ENOMEM; } if (!gadget->is_chipidea) { req->length = 32*1024; sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | qdss->bam_info.usb_bam_pipe_idx; } else { /* non DWC3 BAM requires req->length to be 0 */ req->length = 0; sps_params = (MSM_SPS_MODE | qdss->bam_info.usb_bam_pipe_idx | MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER; } req->udc_priv = sps_params; qdss->endless_req = req; Loading Loading @@ -107,10 +116,12 @@ int set_qdss_data_connection(struct f_qdss *qdss, int enable) NULL, bam_info.data_fifo, NULL); alloc_sps_req(qdss->port.data); if (!gadget->is_chipidea) msm_data_fifo_config(qdss->port.data, bam_info.data_fifo->iova, bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx); init_data(qdss->port.data); res = usb_bam_connect(usb_bam_type, idx, Loading @@ -132,8 +143,14 @@ int set_qdss_data_connection(struct f_qdss *qdss, int enable) static int init_data(struct usb_ep *ep) { struct f_qdss *qdss = ep->driver_data; struct usb_gadget *gadget = qdss->gadget; int res = 0; if (gadget->is_chipidea) { pr_debug("QDSS is used with non DWC3 core\n"); return res; } pr_debug("init_data\n"); res = msm_ep_config(ep, qdss->endless_req); Loading @@ -145,8 +162,13 @@ static int init_data(struct usb_ep *ep) int uninit_data(struct usb_ep *ep) { struct f_qdss *qdss = ep->driver_data; struct usb_gadget *gadget = qdss->gadget; int res = 0; if (gadget->is_chipidea) return res; pr_err("uninit_data\n"); res = msm_ep_unconfig(ep); Loading
include/linux/usb_bam.h +2 −0 Original line number Diff line number Diff line Loading @@ -438,6 +438,7 @@ int get_qdss_bam_info(enum usb_ctrl cur_bam, u8 idx, bool msm_bam_hsic_lpm_ok(void); bool msm_bam_hsic_host_pipe_empty(void); bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable); int msm_do_bam_disable_enable(enum usb_ctrl ctrl); #else static inline int usb_bam_connect(enum usb_ctrl bam, u8 idx, u32 *bam_pipe_idx, unsigned long iova) Loading Loading @@ -543,6 +544,7 @@ static inline bool msm_bam_hsic_lpm_ok(void) { return true; } static inline bool msm_bam_hsic_host_pipe_empty(void) { return true; } static inline bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable) { return true; } int msm_do_bam_disable_enable(enum usb_ctrl ctrl) { return true; } #endif Loading