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

Commit 057d231d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: bam: suspend/resume handshake with the IPA"

parents 2858fdd0 17b10ed2
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;
};

/**