Loading drivers/platform/msm/usb_bam.c +88 −18 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ #define USB_BAM_NR_PORTS 4 #define ARRAY_INDEX_FROM_ADDR(base, addr) ((addr) - (base)) enum usb_bam_sm { USB_BAM_SM_INIT = 0, USB_BAM_SM_PLUG_NOTIFIED, Loading Loading @@ -296,8 +298,7 @@ static void usb_bam_set_inactivity_timer(enum usb_bam bam) */ for (i = 0; i < ctx.max_connections; i++) { pipe_connect = &usb_bam_connections[i]; if (pipe_connect->bam_type == bam && pipe_connect->enabled) { if (pipe_connect->bam_type == bam && pipe_connect->enabled) { pipe = ctx.usb_bam_sps.sps_pipes[i]; break; } Loading Loading @@ -583,6 +584,7 @@ static int connect_pipe_bam2bam_ipa(u8 idx, pipe_connect->activity_notify = ipa_params->activity_notify; pipe_connect->inactivity_notify = ipa_params->inactivity_notify; pipe_connect->priv = ipa_params->priv; pipe_connect->reset_pipe_after_lpm = ipa_params->reset_pipe_after_lpm; /* IPA input parameters */ ipa_in_params.client_bam_hdl = usb_handle; Loading Loading @@ -749,7 +751,7 @@ static int disconnect_pipe(u8 idx) static bool _usb_bam_resume_core(void) { pr_debug("%s: Resuming usb peripheral/host device", __func__); pr_debug("Resuming usb peripheral/host device\n"); if (usb_device) pm_runtime_resume(usb_device); Loading Loading @@ -1081,6 +1083,57 @@ int usb_bam_connect(int idx, u32 *bam_pipe_idx) return 0; } /* This function is in expectation that the SPS team expose similar * functionality. As a result, it is written so that when the * function does become available, it'll have the same (expected) API. */ static int __sps_reset_pipe(struct sps_pipe *pipe, u32 idx) { int ret; struct sps_connect *sps_connection = &ctx.usb_bam_sps.sps_connections[idx]; ret = sps_disconnect(pipe); if (ret) { pr_err("%s: sps_disconnect() failed %d\n", __func__, ret); return ret; } ret = sps_connect(pipe, sps_connection); if (ret < 0) { pr_err("%s: sps_connect() failed %d\n", __func__, ret); return ret; } return 0; } static void reset_pipe_for_resume(struct usb_bam_pipe_connect *pipe_connect) { int ret; u32 idx = ARRAY_INDEX_FROM_ADDR(usb_bam_connections, pipe_connect); struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx]; if (!pipe_connect->reset_pipe_after_lpm || pipe_connect->pipe_type != USB_BAM_PIPE_BAM2BAM) { pr_debug("No need to reset pipe %d\n", idx); return; } ret = __sps_reset_pipe(pipe, idx); if (ret) { pr_err("%s failed to reset the USB sps pipe\n", __func__); return; } ret = ipa_reset_endpoint(pipe_connect->ipa_clnt_hdl); if (ret) { pr_err("%s failed to reset the IPA pipe\n", __func__); return; } } /* Stop PROD transfers in case they were started */ static void stop_prod_transfers(struct usb_bam_pipe_connect *pipe_connect) { Loading Loading @@ -1578,7 +1631,7 @@ static void wait_for_prod_release(enum usb_bam cur_bam) pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret); } static int check_pipes_empty(u8 src_idx, u8 dst_idx) static bool check_pipes_empty(u8 src_idx, u8 dst_idx) { struct sps_pipe *prod_pipe, *cons_pipe; struct usb_bam_pipe_connect *prod_pipe_connect, *cons_pipe_connect; Loading @@ -1596,18 +1649,32 @@ static int check_pipes_empty(u8 src_idx, u8 dst_idx) cons_pipe = ctx.usb_bam_sps.sps_pipes[dst_idx]; pr_debug("prod_pipe=%p, cons_pipe=%p", prod_pipe, cons_pipe); if (!prod_pipe || sps_is_pipe_empty(prod_pipe, &prod_empty) || !cons_pipe || sps_is_pipe_empty(cons_pipe, &cons_empty)) { pr_err("%s: sps_is_pipe_empty failed with\n", __func__); return 1; if (!cons_pipe || (!prod_pipe && prod_pipe_connect->pipe_type == USB_BAM_PIPE_BAM2BAM)) { pr_err("Missing a pipe!\n"); return false; } if (prod_pipe && sps_is_pipe_empty(prod_pipe, &prod_empty)) { pr_err("sps_is_pipe_empty(prod) failed\n"); return false; } else { prod_empty = true; } if (sps_is_pipe_empty(cons_pipe, &cons_empty)) { pr_err("sps_is_pipe_empty(cons) failed\n"); return false; } if (!prod_empty || !cons_empty) { pr_err("%s: pipes not empty prod=%d cond=%d", __func__, pr_err("pipes not empty prod=%d cond=%d", prod_empty, cons_empty); return 0; return false; } return 1; return true; } void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params) Loading Loading @@ -1763,6 +1830,9 @@ static void usb_bam_finish_resume(struct work_struct *w) idx = suspended - 1; dst_idx = info[cur_bam].resume_dst_idx[idx]; pipe_connect = &usb_bam_connections[dst_idx]; spin_unlock(&usb_bam_ipa_handshake_info_lock); reset_pipe_for_resume(pipe_connect); spin_lock(&usb_bam_ipa_handshake_info_lock); if (pipe_connect->cons_stopped) { pr_debug("%s: Starting CONS on %d", __func__, dst_idx); start_cons_transfers(pipe_connect); Loading drivers/usb/gadget/u_bam.c +120 −43 Original line number Diff line number Diff line Loading @@ -122,6 +122,9 @@ struct bam_ch_info { u32 dst_pipe_idx; u8 src_connection_idx; u8 dst_connection_idx; int src_bam_idx; int dst_bam_idx; enum transport_type trans; struct usb_bam_connect_ipa_params ipa_params; Loading Loading @@ -777,9 +780,53 @@ static void gbam_stop_endless_tx(struct gbam_port *port) spin_unlock(&port->port_lock_dl); } /* * This function configured data fifo based on index passed to get bam2bam * configuration. */ static void configure_data_fifo(u8 idx, struct usb_ep *ep, enum usb_bam_pipe_type pipe_type) { struct u_bam_data_connect_info bam_info; struct sps_mem_buffer data_fifo = {0}; if (pipe_type == USB_BAM_PIPE_BAM2BAM) { get_bam2bam_connection_info(idx, &bam_info.usb_bam_handle, &bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx, NULL, &data_fifo); msm_data_fifo_config(ep, data_fifo.phys_base, data_fifo.size, bam_info.usb_bam_pipe_idx); } } static void gbam_start(void *param, enum usb_bam_pipe_dir dir) { struct gbam_port *port = param; struct f_rmnet *dev = NULL; struct usb_gadget *gadget = NULL; struct bam_ch_info *d; if (port) { dev = port_to_rmnet(port->gr); d = &port->data_ch; } else { pr_err("%s: port is NULL\n", __func__); return; } if (dev && dev->cdev) gadget = dev->cdev->gadget; else { pr_err("%s: dev or dev->cdev are NULL\n", __func__); return; } if (dir == USB_TO_PEER_PERIPHERAL) { if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM) Loading @@ -787,6 +834,22 @@ static void gbam_start(void *param, enum usb_bam_pipe_dir dir) else gbam_start_rx(port); } else { if (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_data_fifo(idx, port->port_usb->in, d->dst_pipe_type); } gbam_start_endless_tx(port); } } Loading Loading @@ -998,30 +1061,6 @@ static void gbam_connect_work(struct work_struct *w) pr_debug("%s: done\n", __func__); } /* * This function configured data fifo based on index passed to get bam2bam * configuration. */ static void configure_data_fifo(u8 idx, struct usb_ep *ep, enum usb_bam_pipe_type pipe_type) { struct u_bam_data_connect_info bam_info; struct sps_mem_buffer data_fifo = {0}; if (pipe_type == USB_BAM_PIPE_BAM2BAM) { get_bam2bam_connection_info(idx, &bam_info.usb_bam_handle, &bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx, NULL, &data_fifo); msm_data_fifo_config(ep, data_fifo.phys_base, data_fifo.size, bam_info.usb_bam_pipe_idx); } } static void gbam2bam_connect_work(struct work_struct *w) { struct gbam_port *port = container_of(w, struct gbam_port, connect_w); Loading Loading @@ -1089,6 +1128,9 @@ static void gbam2bam_connect_work(struct work_struct *w) teth_bridge_params.usb_notify_cb; d->ipa_params.priv = teth_bridge_params.private_data; d->ipa_params.reset_pipe_after_lpm = (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)); } d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC; d->ipa_params.skip_ep_cfg = teth_bridge_params.skip_ep_cfg; Loading @@ -1101,18 +1143,16 @@ static void gbam2bam_connect_work(struct work_struct *w) } if (gadget && gadget_is_dwc3(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, d->src_bam_idx = usb_bam_get_connection_idx( gadget->name, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); if (idx < 0) { if (d->src_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_data_fifo(idx, port->port_usb->out, configure_data_fifo(d->src_bam_idx, port->port_usb->out, d->src_pipe_type); } Loading @@ -1120,6 +1160,9 @@ static void gbam2bam_connect_work(struct work_struct *w) if (d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) { d->ipa_params.notify = d->ul_params.teth_cb; d->ipa_params.priv = d->ul_params.teth_priv; d->ipa_params.reset_pipe_after_lpm = (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)); } d->ipa_params.dir = PEER_PERIPHERAL_TO_USB; ret = usb_bam_connect_ipa(&d->ipa_params); Loading @@ -1130,18 +1173,16 @@ static void gbam2bam_connect_work(struct work_struct *w) } if (gadget && gadget_is_dwc3(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, d->dst_bam_idx = usb_bam_get_connection_idx( gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (idx < 0) { if (d->dst_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_data_fifo(idx, port->port_usb->in, configure_data_fifo(d->dst_bam_idx, port->port_usb->in, d->dst_pipe_type); } Loading Loading @@ -1264,10 +1305,18 @@ static void gbam2bam_suspend_work(struct work_struct *w) { struct gbam_port *port = container_of(w, struct gbam_port, suspend_w); struct bam_ch_info *d = &port->data_ch; int ret; pr_debug("%s: suspend work started\n", __func__); usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port); ret = usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port); if (ret) { pr_err("%s(): Failed to register BAM wake callback.\n", __func__); return; } if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { usb_bam_register_start_stop_cbs(d->dst_connection_idx, gbam_start, gbam_stop, port); Loading @@ -1279,13 +1328,41 @@ static void gbam2bam_resume_work(struct work_struct *w) { struct gbam_port *port = container_of(w, struct gbam_port, resume_w); struct bam_ch_info *d = &port->data_ch; struct f_rmnet *dev = NULL; struct usb_gadget *gadget = NULL; int ret; pr_debug("%s: resume work started\n", __func__); if (port) dev = port_to_rmnet(port->gr); if (dev && dev->cdev) { gadget = dev->cdev->gadget; } else { pr_err("Unable to retrieve gadget handle\n"); return; } ret = usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL); if (ret) { pr_err("%s(): Failed to register BAM wake callback.\n", __func__); return; } usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL); if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { if (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)) { configure_data_fifo(d->src_bam_idx, port->port_usb->out, d->src_pipe_type); configure_data_fifo(d->dst_bam_idx, port->port_usb->in, d->dst_pipe_type); msm_dwc3_reset_dbm_ep(port->port_usb->in); } usb_bam_resume(&d->ipa_params); } } static int gbam_peer_reset_cb(void *param) { Loading drivers/usb/gadget/u_bam_data.c +67 −15 Original line number Diff line number Diff line Loading @@ -81,6 +81,8 @@ struct bam_data_ch_info { u32 dst_pipe_idx; u8 src_connection_idx; u8 dst_connection_idx; int src_bam_idx; int dst_bam_idx; enum function_type func_type; enum transport_type trans; Loading Loading @@ -653,6 +655,10 @@ static void bam2bam_data_connect_work(struct work_struct *w) bam_data_ipa_sys2bam_notify_cb; d->ul_params.teth_priv = d->ipa_params.priv; d->ipa_params.priv = &d->ul_params; } else { d->ipa_params.reset_pipe_after_lpm = (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)); } ret = usb_bam_connect_ipa(&d->ipa_params); Loading @@ -665,18 +671,18 @@ static void bam2bam_data_connect_work(struct work_struct *w) d_port->ipa_consumer_ep = d->ipa_params.ipa_cons_ep_idx; if (gadget_is_dwc3(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, d->src_bam_idx = usb_bam_get_connection_idx( gadget->name, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); if (idx < 0) { if (d->src_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_usb_data_fifo(idx, port->port_usb->out, configure_usb_data_fifo(d->src_bam_idx, port->port_usb->out, d->src_pipe_type); } Loading @@ -699,6 +705,13 @@ static void bam2bam_data_connect_work(struct work_struct *w) d->ipa_params.skip_ep_cfg = rndis_qc_get_skip_ep_config(); } if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM) { d->ipa_params.reset_pipe_after_lpm = (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)); } ret = usb_bam_connect_ipa(&d->ipa_params); if (ret) { pr_err("%s: usb_bam_connect_ipa failed: err:%d\n", Loading @@ -712,18 +725,18 @@ static void bam2bam_data_connect_work(struct work_struct *w) d_port->ipa_consumer_ep); if (gadget_is_dwc3(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, d->dst_bam_idx = usb_bam_get_connection_idx( gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (idx < 0) { if (d->dst_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_usb_data_fifo(idx, port->port_usb->in, configure_usb_data_fifo(d->dst_bam_idx, port->port_usb->in, d->dst_pipe_type); } Loading Loading @@ -1204,6 +1217,16 @@ static int bam_data_wake_cb(void *param) static void bam_data_start(void *param, enum usb_bam_pipe_dir dir) { struct bam_data_port *port = param; struct data_port *d_port = port->port_usb; struct bam_data_ch_info *d = &port->data_ch; struct usb_gadget *gadget; if (!d_port || !d_port->cdev || !d_port->cdev->gadget) { pr_err("%s:d_port,cdev or gadget is NULL\n", __func__); return; } gadget = d_port->cdev->gadget; if (dir == USB_TO_PEER_PERIPHERAL) { if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM) Loading @@ -1211,6 +1234,22 @@ static void bam_data_start(void *param, enum usb_bam_pipe_dir dir) else bam_data_start_rx(port); } else { if (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_data_fifo(idx, port->port_usb->in, d->dst_pipe_type); } bam_data_start_endless_tx(port); } Loading Loading @@ -1293,6 +1332,8 @@ static void bam2bam_data_resume_work(struct work_struct *w) struct bam_data_port *port = container_of(w, struct bam_data_port, resume_w); struct bam_data_ch_info *d = &port->data_ch; struct data_port *d_port = port->port_usb; struct usb_gadget *gadget = d_port->cdev->gadget; int ret; pr_debug("%s: resume work started\n", __func__); Loading @@ -1309,9 +1350,20 @@ static void bam2bam_data_resume_work(struct work_struct *w) return; } if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { if (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)) { configure_usb_data_fifo(d->src_bam_idx, port->port_usb->out, d->src_pipe_type); configure_usb_data_fifo(d->dst_bam_idx, port->port_usb->in, d->dst_pipe_type); msm_dwc3_reset_dbm_ep(port->port_usb->in); } usb_bam_resume(&d->ipa_params); } } void u_bam_data_set_max_xfer_size(u32 max_transfer_size) { Loading include/linux/usb/msm_hsusb.h +13 −0 Original line number Diff line number Diff line Loading @@ -615,6 +615,8 @@ int msm_ep_unconfig(struct usb_ep *ep); void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable); int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr, u32 size, u8 dst_pipe_idx); bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget); int msm_dwc3_reset_dbm_ep(struct usb_ep *ep); void msm_dwc3_restart_usb_session(struct usb_gadget *gadget); Loading Loading @@ -652,5 +654,16 @@ static inline int msm_register_usb_ext_notification( { return -ENODEV; } static inline bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget) { return false; } static inline int msm_dwc3_reset_dbm_ep(struct usb_ep *ep) { return -ENODEV; } #endif #endif include/linux/usb_bam.h +2 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ struct usb_bam_connect_ipa_params { int (*activity_notify)(void *priv); int (*inactivity_notify)(void *priv); bool skip_ep_cfg; bool reset_pipe_after_lpm; }; /** Loading Loading @@ -162,6 +163,7 @@ struct usb_bam_pipe_connect { void (*start)(void *, enum usb_bam_pipe_dir); void (*stop)(void *, enum usb_bam_pipe_dir); void *start_stop_param; bool reset_pipe_after_lpm; }; /** Loading Loading
drivers/platform/msm/usb_bam.c +88 −18 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ #define USB_BAM_NR_PORTS 4 #define ARRAY_INDEX_FROM_ADDR(base, addr) ((addr) - (base)) enum usb_bam_sm { USB_BAM_SM_INIT = 0, USB_BAM_SM_PLUG_NOTIFIED, Loading Loading @@ -296,8 +298,7 @@ static void usb_bam_set_inactivity_timer(enum usb_bam bam) */ for (i = 0; i < ctx.max_connections; i++) { pipe_connect = &usb_bam_connections[i]; if (pipe_connect->bam_type == bam && pipe_connect->enabled) { if (pipe_connect->bam_type == bam && pipe_connect->enabled) { pipe = ctx.usb_bam_sps.sps_pipes[i]; break; } Loading Loading @@ -583,6 +584,7 @@ static int connect_pipe_bam2bam_ipa(u8 idx, pipe_connect->activity_notify = ipa_params->activity_notify; pipe_connect->inactivity_notify = ipa_params->inactivity_notify; pipe_connect->priv = ipa_params->priv; pipe_connect->reset_pipe_after_lpm = ipa_params->reset_pipe_after_lpm; /* IPA input parameters */ ipa_in_params.client_bam_hdl = usb_handle; Loading Loading @@ -749,7 +751,7 @@ static int disconnect_pipe(u8 idx) static bool _usb_bam_resume_core(void) { pr_debug("%s: Resuming usb peripheral/host device", __func__); pr_debug("Resuming usb peripheral/host device\n"); if (usb_device) pm_runtime_resume(usb_device); Loading Loading @@ -1081,6 +1083,57 @@ int usb_bam_connect(int idx, u32 *bam_pipe_idx) return 0; } /* This function is in expectation that the SPS team expose similar * functionality. As a result, it is written so that when the * function does become available, it'll have the same (expected) API. */ static int __sps_reset_pipe(struct sps_pipe *pipe, u32 idx) { int ret; struct sps_connect *sps_connection = &ctx.usb_bam_sps.sps_connections[idx]; ret = sps_disconnect(pipe); if (ret) { pr_err("%s: sps_disconnect() failed %d\n", __func__, ret); return ret; } ret = sps_connect(pipe, sps_connection); if (ret < 0) { pr_err("%s: sps_connect() failed %d\n", __func__, ret); return ret; } return 0; } static void reset_pipe_for_resume(struct usb_bam_pipe_connect *pipe_connect) { int ret; u32 idx = ARRAY_INDEX_FROM_ADDR(usb_bam_connections, pipe_connect); struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx]; if (!pipe_connect->reset_pipe_after_lpm || pipe_connect->pipe_type != USB_BAM_PIPE_BAM2BAM) { pr_debug("No need to reset pipe %d\n", idx); return; } ret = __sps_reset_pipe(pipe, idx); if (ret) { pr_err("%s failed to reset the USB sps pipe\n", __func__); return; } ret = ipa_reset_endpoint(pipe_connect->ipa_clnt_hdl); if (ret) { pr_err("%s failed to reset the IPA pipe\n", __func__); return; } } /* Stop PROD transfers in case they were started */ static void stop_prod_transfers(struct usb_bam_pipe_connect *pipe_connect) { Loading Loading @@ -1578,7 +1631,7 @@ static void wait_for_prod_release(enum usb_bam cur_bam) pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret); } static int check_pipes_empty(u8 src_idx, u8 dst_idx) static bool check_pipes_empty(u8 src_idx, u8 dst_idx) { struct sps_pipe *prod_pipe, *cons_pipe; struct usb_bam_pipe_connect *prod_pipe_connect, *cons_pipe_connect; Loading @@ -1596,18 +1649,32 @@ static int check_pipes_empty(u8 src_idx, u8 dst_idx) cons_pipe = ctx.usb_bam_sps.sps_pipes[dst_idx]; pr_debug("prod_pipe=%p, cons_pipe=%p", prod_pipe, cons_pipe); if (!prod_pipe || sps_is_pipe_empty(prod_pipe, &prod_empty) || !cons_pipe || sps_is_pipe_empty(cons_pipe, &cons_empty)) { pr_err("%s: sps_is_pipe_empty failed with\n", __func__); return 1; if (!cons_pipe || (!prod_pipe && prod_pipe_connect->pipe_type == USB_BAM_PIPE_BAM2BAM)) { pr_err("Missing a pipe!\n"); return false; } if (prod_pipe && sps_is_pipe_empty(prod_pipe, &prod_empty)) { pr_err("sps_is_pipe_empty(prod) failed\n"); return false; } else { prod_empty = true; } if (sps_is_pipe_empty(cons_pipe, &cons_empty)) { pr_err("sps_is_pipe_empty(cons) failed\n"); return false; } if (!prod_empty || !cons_empty) { pr_err("%s: pipes not empty prod=%d cond=%d", __func__, pr_err("pipes not empty prod=%d cond=%d", prod_empty, cons_empty); return 0; return false; } return 1; return true; } void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params) Loading Loading @@ -1763,6 +1830,9 @@ static void usb_bam_finish_resume(struct work_struct *w) idx = suspended - 1; dst_idx = info[cur_bam].resume_dst_idx[idx]; pipe_connect = &usb_bam_connections[dst_idx]; spin_unlock(&usb_bam_ipa_handshake_info_lock); reset_pipe_for_resume(pipe_connect); spin_lock(&usb_bam_ipa_handshake_info_lock); if (pipe_connect->cons_stopped) { pr_debug("%s: Starting CONS on %d", __func__, dst_idx); start_cons_transfers(pipe_connect); Loading
drivers/usb/gadget/u_bam.c +120 −43 Original line number Diff line number Diff line Loading @@ -122,6 +122,9 @@ struct bam_ch_info { u32 dst_pipe_idx; u8 src_connection_idx; u8 dst_connection_idx; int src_bam_idx; int dst_bam_idx; enum transport_type trans; struct usb_bam_connect_ipa_params ipa_params; Loading Loading @@ -777,9 +780,53 @@ static void gbam_stop_endless_tx(struct gbam_port *port) spin_unlock(&port->port_lock_dl); } /* * This function configured data fifo based on index passed to get bam2bam * configuration. */ static void configure_data_fifo(u8 idx, struct usb_ep *ep, enum usb_bam_pipe_type pipe_type) { struct u_bam_data_connect_info bam_info; struct sps_mem_buffer data_fifo = {0}; if (pipe_type == USB_BAM_PIPE_BAM2BAM) { get_bam2bam_connection_info(idx, &bam_info.usb_bam_handle, &bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx, NULL, &data_fifo); msm_data_fifo_config(ep, data_fifo.phys_base, data_fifo.size, bam_info.usb_bam_pipe_idx); } } static void gbam_start(void *param, enum usb_bam_pipe_dir dir) { struct gbam_port *port = param; struct f_rmnet *dev = NULL; struct usb_gadget *gadget = NULL; struct bam_ch_info *d; if (port) { dev = port_to_rmnet(port->gr); d = &port->data_ch; } else { pr_err("%s: port is NULL\n", __func__); return; } if (dev && dev->cdev) gadget = dev->cdev->gadget; else { pr_err("%s: dev or dev->cdev are NULL\n", __func__); return; } if (dir == USB_TO_PEER_PERIPHERAL) { if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM) Loading @@ -787,6 +834,22 @@ static void gbam_start(void *param, enum usb_bam_pipe_dir dir) else gbam_start_rx(port); } else { if (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_data_fifo(idx, port->port_usb->in, d->dst_pipe_type); } gbam_start_endless_tx(port); } } Loading Loading @@ -998,30 +1061,6 @@ static void gbam_connect_work(struct work_struct *w) pr_debug("%s: done\n", __func__); } /* * This function configured data fifo based on index passed to get bam2bam * configuration. */ static void configure_data_fifo(u8 idx, struct usb_ep *ep, enum usb_bam_pipe_type pipe_type) { struct u_bam_data_connect_info bam_info; struct sps_mem_buffer data_fifo = {0}; if (pipe_type == USB_BAM_PIPE_BAM2BAM) { get_bam2bam_connection_info(idx, &bam_info.usb_bam_handle, &bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx, NULL, &data_fifo); msm_data_fifo_config(ep, data_fifo.phys_base, data_fifo.size, bam_info.usb_bam_pipe_idx); } } static void gbam2bam_connect_work(struct work_struct *w) { struct gbam_port *port = container_of(w, struct gbam_port, connect_w); Loading Loading @@ -1089,6 +1128,9 @@ static void gbam2bam_connect_work(struct work_struct *w) teth_bridge_params.usb_notify_cb; d->ipa_params.priv = teth_bridge_params.private_data; d->ipa_params.reset_pipe_after_lpm = (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)); } d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC; d->ipa_params.skip_ep_cfg = teth_bridge_params.skip_ep_cfg; Loading @@ -1101,18 +1143,16 @@ static void gbam2bam_connect_work(struct work_struct *w) } if (gadget && gadget_is_dwc3(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, d->src_bam_idx = usb_bam_get_connection_idx( gadget->name, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); if (idx < 0) { if (d->src_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_data_fifo(idx, port->port_usb->out, configure_data_fifo(d->src_bam_idx, port->port_usb->out, d->src_pipe_type); } Loading @@ -1120,6 +1160,9 @@ static void gbam2bam_connect_work(struct work_struct *w) if (d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) { d->ipa_params.notify = d->ul_params.teth_cb; d->ipa_params.priv = d->ul_params.teth_priv; d->ipa_params.reset_pipe_after_lpm = (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)); } d->ipa_params.dir = PEER_PERIPHERAL_TO_USB; ret = usb_bam_connect_ipa(&d->ipa_params); Loading @@ -1130,18 +1173,16 @@ static void gbam2bam_connect_work(struct work_struct *w) } if (gadget && gadget_is_dwc3(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, d->dst_bam_idx = usb_bam_get_connection_idx( gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (idx < 0) { if (d->dst_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_data_fifo(idx, port->port_usb->in, configure_data_fifo(d->dst_bam_idx, port->port_usb->in, d->dst_pipe_type); } Loading Loading @@ -1264,10 +1305,18 @@ static void gbam2bam_suspend_work(struct work_struct *w) { struct gbam_port *port = container_of(w, struct gbam_port, suspend_w); struct bam_ch_info *d = &port->data_ch; int ret; pr_debug("%s: suspend work started\n", __func__); usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port); ret = usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port); if (ret) { pr_err("%s(): Failed to register BAM wake callback.\n", __func__); return; } if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { usb_bam_register_start_stop_cbs(d->dst_connection_idx, gbam_start, gbam_stop, port); Loading @@ -1279,13 +1328,41 @@ static void gbam2bam_resume_work(struct work_struct *w) { struct gbam_port *port = container_of(w, struct gbam_port, resume_w); struct bam_ch_info *d = &port->data_ch; struct f_rmnet *dev = NULL; struct usb_gadget *gadget = NULL; int ret; pr_debug("%s: resume work started\n", __func__); if (port) dev = port_to_rmnet(port->gr); if (dev && dev->cdev) { gadget = dev->cdev->gadget; } else { pr_err("Unable to retrieve gadget handle\n"); return; } ret = usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL); if (ret) { pr_err("%s(): Failed to register BAM wake callback.\n", __func__); return; } usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL); if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { if (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)) { configure_data_fifo(d->src_bam_idx, port->port_usb->out, d->src_pipe_type); configure_data_fifo(d->dst_bam_idx, port->port_usb->in, d->dst_pipe_type); msm_dwc3_reset_dbm_ep(port->port_usb->in); } usb_bam_resume(&d->ipa_params); } } static int gbam_peer_reset_cb(void *param) { Loading
drivers/usb/gadget/u_bam_data.c +67 −15 Original line number Diff line number Diff line Loading @@ -81,6 +81,8 @@ struct bam_data_ch_info { u32 dst_pipe_idx; u8 src_connection_idx; u8 dst_connection_idx; int src_bam_idx; int dst_bam_idx; enum function_type func_type; enum transport_type trans; Loading Loading @@ -653,6 +655,10 @@ static void bam2bam_data_connect_work(struct work_struct *w) bam_data_ipa_sys2bam_notify_cb; d->ul_params.teth_priv = d->ipa_params.priv; d->ipa_params.priv = &d->ul_params; } else { d->ipa_params.reset_pipe_after_lpm = (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)); } ret = usb_bam_connect_ipa(&d->ipa_params); Loading @@ -665,18 +671,18 @@ static void bam2bam_data_connect_work(struct work_struct *w) d_port->ipa_consumer_ep = d->ipa_params.ipa_cons_ep_idx; if (gadget_is_dwc3(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, d->src_bam_idx = usb_bam_get_connection_idx( gadget->name, IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0); if (idx < 0) { if (d->src_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_usb_data_fifo(idx, port->port_usb->out, configure_usb_data_fifo(d->src_bam_idx, port->port_usb->out, d->src_pipe_type); } Loading @@ -699,6 +705,13 @@ static void bam2bam_data_connect_work(struct work_struct *w) d->ipa_params.skip_ep_cfg = rndis_qc_get_skip_ep_config(); } if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM) { d->ipa_params.reset_pipe_after_lpm = (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)); } ret = usb_bam_connect_ipa(&d->ipa_params); if (ret) { pr_err("%s: usb_bam_connect_ipa failed: err:%d\n", Loading @@ -712,18 +725,18 @@ static void bam2bam_data_connect_work(struct work_struct *w) d_port->ipa_consumer_ep); if (gadget_is_dwc3(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, d->dst_bam_idx = usb_bam_get_connection_idx( gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (idx < 0) { if (d->dst_bam_idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_usb_data_fifo(idx, port->port_usb->in, configure_usb_data_fifo(d->dst_bam_idx, port->port_usb->in, d->dst_pipe_type); } Loading Loading @@ -1204,6 +1217,16 @@ static int bam_data_wake_cb(void *param) static void bam_data_start(void *param, enum usb_bam_pipe_dir dir) { struct bam_data_port *port = param; struct data_port *d_port = port->port_usb; struct bam_data_ch_info *d = &port->data_ch; struct usb_gadget *gadget; if (!d_port || !d_port->cdev || !d_port->cdev->gadget) { pr_err("%s:d_port,cdev or gadget is NULL\n", __func__); return; } gadget = d_port->cdev->gadget; if (dir == USB_TO_PEER_PERIPHERAL) { if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM) Loading @@ -1211,6 +1234,22 @@ static void bam_data_start(void *param, enum usb_bam_pipe_dir dir) else bam_data_start_rx(port); } else { if (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)) { u8 idx; idx = usb_bam_get_connection_idx(gadget->name, IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0); if (idx < 0) { pr_err("%s: get_connection_idx failed\n", __func__); return; } configure_data_fifo(idx, port->port_usb->in, d->dst_pipe_type); } bam_data_start_endless_tx(port); } Loading Loading @@ -1293,6 +1332,8 @@ static void bam2bam_data_resume_work(struct work_struct *w) struct bam_data_port *port = container_of(w, struct bam_data_port, resume_w); struct bam_data_ch_info *d = &port->data_ch; struct data_port *d_port = port->port_usb; struct usb_gadget *gadget = d_port->cdev->gadget; int ret; pr_debug("%s: resume work started\n", __func__); Loading @@ -1309,9 +1350,20 @@ static void bam2bam_data_resume_work(struct work_struct *w) return; } if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) { if (gadget_is_dwc3(gadget) && msm_dwc3_reset_ep_after_lpm(gadget)) { configure_usb_data_fifo(d->src_bam_idx, port->port_usb->out, d->src_pipe_type); configure_usb_data_fifo(d->dst_bam_idx, port->port_usb->in, d->dst_pipe_type); msm_dwc3_reset_dbm_ep(port->port_usb->in); } usb_bam_resume(&d->ipa_params); } } void u_bam_data_set_max_xfer_size(u32 max_transfer_size) { Loading
include/linux/usb/msm_hsusb.h +13 −0 Original line number Diff line number Diff line Loading @@ -615,6 +615,8 @@ int msm_ep_unconfig(struct usb_ep *ep); void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable); int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr, u32 size, u8 dst_pipe_idx); bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget); int msm_dwc3_reset_dbm_ep(struct usb_ep *ep); void msm_dwc3_restart_usb_session(struct usb_gadget *gadget); Loading Loading @@ -652,5 +654,16 @@ static inline int msm_register_usb_ext_notification( { return -ENODEV; } static inline bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget) { return false; } static inline int msm_dwc3_reset_dbm_ep(struct usb_ep *ep) { return -ENODEV; } #endif #endif
include/linux/usb_bam.h +2 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ struct usb_bam_connect_ipa_params { int (*activity_notify)(void *priv); int (*inactivity_notify)(void *priv); bool skip_ep_cfg; bool reset_pipe_after_lpm; }; /** Loading Loading @@ -162,6 +163,7 @@ struct usb_bam_pipe_connect { void (*start)(void *, enum usb_bam_pipe_dir); void (*stop)(void *, enum usb_bam_pipe_dir); void *start_stop_param; bool reset_pipe_after_lpm; }; /** Loading