Loading arch/arm/boot/dts/qcom/msm8940.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ qcom,usbbam@78c4000 { qcom,enable-hsusb-bam-on-boot; /delete-property/ qcom,reset-bam-on-disconnect; /delete-node/ qcom,pipe0; qcom,pipe0 { label = "hsusb-ipa-out-0"; Loading arch/arm/boot/dts/qcom/msm8952.dtsi +0 −1 Original line number Diff line number Diff line Loading @@ -1069,7 +1069,6 @@ qcom,ignore-core-reset-ack; qcom,disable-clk-gating; qcom,usb-bam-max-mbps-highspeed = <400>; qcom,reset-bam-on-disconnect; qcom,pipe0 { label = "hsusb-ipa-out-0"; Loading drivers/platform/msm/usb_bam.c +127 −5 Original line number Diff line number Diff line Loading @@ -2644,12 +2644,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 @@ -3053,6 +3053,7 @@ static int usb_bam_init(struct platform_device *pdev) if (pdata->enable_hsusb_bam_on_boot && 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; } ret = sps_register_bam_device(&props, &ctx->h_bam); Loading Loading @@ -3395,6 +3396,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_platform_data *pdata; if (!ctx->usb_bam_pdev) return 0; pdata = ctx->usb_bam_pdev->dev.platform_data; if ((bam != CI_CTRL) || !pdata->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_platform_data *pdata; Loading drivers/usb/gadget/composite.c +21 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,9 @@ #include <linux/device.h> #include <linux/utsname.h> #include "gadget_chips.h" #include <linux/usb/composite.h> #include <linux/usb/msm_hsusb.h> #include <asm/unaligned.h> #include "u_os_desc.h" Loading Loading @@ -722,6 +724,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 @@ -1023,8 +1030,14 @@ void usb_remove_config(struct usb_composite_dev *cdev, return; } if (cdev->config == config) if (cdev->config == config) { if (!gadget_is_dwc3(cdev->gadget) && !cdev->suspended) { spin_unlock_irqrestore(&cdev->lock, flags); msm_do_bam_disable_enable(CI_CTRL); spin_lock_irqsave(&cdev->lock, flags); } reset_config(cdev); } list_del(&config->list); Loading Loading @@ -2015,8 +2028,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_dwc3(gadget) && !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_bam.c +9 −9 Original line number Diff line number Diff line Loading @@ -2091,6 +2091,15 @@ void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans) spin_unlock(&port->port_lock_dl); spin_unlock_irqrestore(&port->port_lock_ul, flags_ul); usb_ep_disable(gr->in); if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) { spin_lock_irqsave(&port->port_lock_dl, flags_dl); if (d->tx_req) { usb_ep_free_request(gr->in, d->tx_req); d->tx_req = NULL; } spin_unlock_irqrestore(&port->port_lock_dl, flags_dl); } /* disable endpoints */ if (gr->out) { usb_ep_disable(gr->out); Loading @@ -2103,15 +2112,6 @@ void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans) spin_unlock_irqrestore(&port->port_lock_ul, flags_ul); } } usb_ep_disable(gr->in); if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) { spin_lock_irqsave(&port->port_lock_dl, flags_dl); if (d->tx_req) { usb_ep_free_request(gr->in, d->tx_req); d->tx_req = NULL; } spin_unlock_irqrestore(&port->port_lock_dl, flags_dl); } /* * Set endless flag to false as USB Endpoint is already Loading Loading
arch/arm/boot/dts/qcom/msm8940.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ qcom,usbbam@78c4000 { qcom,enable-hsusb-bam-on-boot; /delete-property/ qcom,reset-bam-on-disconnect; /delete-node/ qcom,pipe0; qcom,pipe0 { label = "hsusb-ipa-out-0"; Loading
arch/arm/boot/dts/qcom/msm8952.dtsi +0 −1 Original line number Diff line number Diff line Loading @@ -1069,7 +1069,6 @@ qcom,ignore-core-reset-ack; qcom,disable-clk-gating; qcom,usb-bam-max-mbps-highspeed = <400>; qcom,reset-bam-on-disconnect; qcom,pipe0 { label = "hsusb-ipa-out-0"; Loading
drivers/platform/msm/usb_bam.c +127 −5 Original line number Diff line number Diff line Loading @@ -2644,12 +2644,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 @@ -3053,6 +3053,7 @@ static int usb_bam_init(struct platform_device *pdev) if (pdata->enable_hsusb_bam_on_boot && 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; } ret = sps_register_bam_device(&props, &ctx->h_bam); Loading Loading @@ -3395,6 +3396,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_platform_data *pdata; if (!ctx->usb_bam_pdev) return 0; pdata = ctx->usb_bam_pdev->dev.platform_data; if ((bam != CI_CTRL) || !pdata->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_platform_data *pdata; Loading
drivers/usb/gadget/composite.c +21 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,9 @@ #include <linux/device.h> #include <linux/utsname.h> #include "gadget_chips.h" #include <linux/usb/composite.h> #include <linux/usb/msm_hsusb.h> #include <asm/unaligned.h> #include "u_os_desc.h" Loading Loading @@ -722,6 +724,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 @@ -1023,8 +1030,14 @@ void usb_remove_config(struct usb_composite_dev *cdev, return; } if (cdev->config == config) if (cdev->config == config) { if (!gadget_is_dwc3(cdev->gadget) && !cdev->suspended) { spin_unlock_irqrestore(&cdev->lock, flags); msm_do_bam_disable_enable(CI_CTRL); spin_lock_irqsave(&cdev->lock, flags); } reset_config(cdev); } list_del(&config->list); Loading Loading @@ -2015,8 +2028,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_dwc3(gadget) && !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_bam.c +9 −9 Original line number Diff line number Diff line Loading @@ -2091,6 +2091,15 @@ void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans) spin_unlock(&port->port_lock_dl); spin_unlock_irqrestore(&port->port_lock_ul, flags_ul); usb_ep_disable(gr->in); if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) { spin_lock_irqsave(&port->port_lock_dl, flags_dl); if (d->tx_req) { usb_ep_free_request(gr->in, d->tx_req); d->tx_req = NULL; } spin_unlock_irqrestore(&port->port_lock_dl, flags_dl); } /* disable endpoints */ if (gr->out) { usb_ep_disable(gr->out); Loading @@ -2103,15 +2112,6 @@ void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans) spin_unlock_irqrestore(&port->port_lock_ul, flags_ul); } } usb_ep_disable(gr->in); if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) { spin_lock_irqsave(&port->port_lock_dl, flags_dl); if (d->tx_req) { usb_ep_free_request(gr->in, d->tx_req); d->tx_req = NULL; } spin_unlock_irqrestore(&port->port_lock_dl, flags_dl); } /* * Set endless flag to false as USB Endpoint is already Loading