Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17b10ed2 authored by Bar Weiner's avatar Bar Weiner Committed by Gerrit - the friendly Code Review server
Browse files

usb: bam: suspend/resume handshake with the IPA



When going to suspend, there is the need to perform
a handshake with the IPA. Furthermore, due to a
hardware bug in the DBM, there is also a need to
reset the DBM ep and corresponding BAM pipe.

This patch exposes the need (or lack thereof) to perform
the DBM and BAM reset, as well as incorporates this reset
into the overall flow of handshaking with the IPA

Change-Id: I4c7159bd292799122785ab019a844822efe46d5c
Signed-off-by: default avatarDov Levenglick <dovl@codeaurora.org>
Signed-off-by: default avatarBar Weiner <bweiner@codeaurora.org>
parent 68766e4f
Loading
Loading
Loading
Loading
+88 −18
Original line number Diff line number Diff line
@@ -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,
@@ -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;
		}
@@ -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;
@@ -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);
@@ -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)
{
@@ -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;
@@ -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)
@@ -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);
+120 −43
Original line number Diff line number Diff line
@@ -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;

@@ -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)
@@ -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);
	}
}
@@ -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);
@@ -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;
@@ -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);
		}

@@ -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);
@@ -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);
		}

@@ -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);
@@ -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)
{
+67 −15
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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);
		}

@@ -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",
@@ -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);
		}

@@ -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)
@@ -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);
	}

@@ -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__);
@@ -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)
{
+13 −0
Original line number Diff line number Diff line
@@ -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);

@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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;
};

/**
@@ -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;
};

/**