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

Commit 48d55840 authored by Hemant Kumar's avatar Hemant Kumar
Browse files

usb: u_bam_data: Directly call suspend/resume APIs from function suspend



Suspend APIs for BAM based functions mbim, ecm and rndis call
bam_data_disconnect() if remote wakeup is disabled otherwise call
bam_data_suspend(). Similarly resume APIs call bam_data_connect() if remote
wakeup is disabled otherwise call bam_data_resume(). Move disconnect and
connect calls inside bam_data_suspend() and bam_data_resume() respectively
and directly call bam_data_suspend() and bam_data_resume() from function
driver suspend.

Change-Id: Icd3f2382046b890c4a445566fd8ad43f57ea1246
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
parent df5046b7
Loading
Loading
Loading
Loading
+19 −110
Original line number Diff line number Diff line
@@ -118,9 +118,6 @@ struct f_mbim {
	struct mbim_ep_descs		fs;
	struct mbim_ep_descs		hs;

	const struct usb_endpoint_descriptor *in_ep_desc_backup;
	const struct usb_endpoint_descriptor *out_ep_desc_backup;

	u8				ctrl_id, data_id;
	bool				data_interface_up;

@@ -720,65 +717,6 @@ static int mbim_bam_setup(int no_ports)
	return 0;
}

static int mbim_bam_connect(struct f_mbim *dev)
{
	int ret;
	u8 src_connection_idx, dst_connection_idx;
	struct usb_gadget *gadget = dev->cdev->gadget;
	enum peer_bam bam_name = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
							IPA_P_BAM : A2_P_BAM;
	int port_num;

	pr_info("dev:%p portno:%d\n", dev, dev->port_num);

	port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, MBIM_DEFAULT_PORT);
	if (port_num < 0)
		return port_num;
	ret = bam2bam_data_port_select(port_num);
	if (ret) {
		pr_err("mbim port select failed err: %d\n", ret);
		return ret;
	}

	src_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name,
		USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, dev->port_num);
	dst_connection_idx = usb_bam_get_connection_idx(gadget->name, bam_name,
		PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, dev->port_num);
	if (src_connection_idx < 0 || dst_connection_idx < 0) {
		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
		return ret;
	}

	port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, dev->port_num);
	if (port_num < 0)
		return port_num;
	ret = bam_data_connect(&dev->bam_port, port_num,
		dev->xport, src_connection_idx, dst_connection_idx,
		USB_FUNC_MBIM);

	if (ret) {
		pr_err("bam_data_setup failed: err:%d\n",
				ret);
		return ret;
	}

	pr_info("mbim bam connected\n");
	return 0;
}

static int mbim_bam_disconnect(struct f_mbim *dev)
{
	int port_num;

	pr_info("%s - dev:%p port:%d\n", __func__, dev, dev->port_num);
	port_num = u_bam_data_func_to_port(USB_FUNC_MBIM, dev->port_num);
	if (port_num < 0)
		return port_num;
	bam_data_disconnect(&dev->bam_port, port_num);

	return 0;
}

/* -------------------------------------------------------------------------*/

static inline void mbim_reset_values(struct f_mbim *mbim)
@@ -1353,9 +1291,14 @@ static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
					}
				}

				pr_debug("Activate mbim\n");
				mbim_bam_connect(mbim);

				ret = bam_data_connect(&mbim->bam_port,
					mbim->xport, mbim->port_num,
					USB_FUNC_MBIM);
				if (ret) {
					pr_err("bam_data_setup failed:err:%d\n",
							ret);
					goto fail;
				}
			} else {
				pr_info("PORTS already SET\n");
			}
@@ -1366,7 +1309,8 @@ static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
			 * perform bam data disconnect handshake upon usb
			 * disconnect
			 */
			mbim_bam_disconnect(mbim);
			bam_data_disconnect(&mbim->bam_port, USB_FUNC_MBIM,
					mbim->port_num);
			if (mbim->xport == USB_GADGET_XPORT_BAM2BAM_IPA &&
					mbim->data_interface_up &&
					gadget_is_dwc3(cdev->gadget)) {
@@ -1444,7 +1388,7 @@ static void mbim_disable(struct usb_function *f)
		msm_ep_unconfig(mbim->bam_port.in);
	}

	mbim_bam_disconnect(mbim);
	bam_data_disconnect(&mbim->bam_port, USB_FUNC_MBIM, mbim->port_num);

	mbim->data_interface_up = false;
	pr_info("mbim deactivated\n");
@@ -1456,7 +1400,6 @@ static void mbim_suspend(struct usb_function *f)
{
	bool remote_wakeup_allowed;
	struct f_mbim	*mbim = func_to_mbim(f);
	int port_num;

	pr_info("mbim suspended\n");

@@ -1481,39 +1424,17 @@ static void mbim_suspend(struct usb_function *f)
		return;
	}

	if (remote_wakeup_allowed) {
		port_num = u_bam_data_func_to_port(USB_FUNC_MBIM,
				MBIM_ACTIVE_PORT);
		if (port_num < 0)
			return;
		bam_data_suspend(port_num);
	} else {
		/*
		 * When remote wakeup is disabled, IPA BAM is disconnected
		 * because it cannot send new data until the USB bus is resumed.
		 * Endpoint descriptors info is saved before it gets reset by
		 * the BAM disconnect API. This lets us restore this info when
		 * the USB bus is resumed.
		 */
		if (mbim->bam_port.in->desc)
			mbim->in_ep_desc_backup  = mbim->bam_port.in->desc;

		if (mbim->bam_port.out->desc)
			mbim->out_ep_desc_backup = mbim->bam_port.out->desc;

		pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p",
			mbim->in_ep_desc_backup, mbim->out_ep_desc_backup);

	if (!remote_wakeup_allowed)
		atomic_set(&mbim->online, 0);
		mbim_bam_disconnect(mbim);
	}

	bam_data_suspend(&mbim->bam_port, mbim->port_num, USB_FUNC_MBIM,
			remote_wakeup_allowed);
}

static void mbim_resume(struct usb_function *f)
{
	bool remote_wakeup_allowed;
	struct f_mbim	*mbim = func_to_mbim(f);
	int port_num;

	pr_info("mbim resumed\n");

@@ -1536,23 +1457,11 @@ static void mbim_resume(struct usb_function *f)
		return;
	}

	if (remote_wakeup_allowed) {
		port_num = u_bam_data_func_to_port(USB_FUNC_MBIM,
						   MBIM_ACTIVE_PORT);
		if (port_num < 0)
			return;
		bam_data_resume(port_num);
	} else {
		/* Restore endpoint descriptors info. */
		mbim->bam_port.in->desc  = mbim->in_ep_desc_backup;
		mbim->bam_port.out->desc = mbim->out_ep_desc_backup;

		pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p",
			mbim->in_ep_desc_backup, mbim->out_ep_desc_backup);

	if (!remote_wakeup_allowed)
		atomic_set(&mbim->online, 1);
		mbim_bam_connect(mbim);
	}

	bam_data_resume(&mbim->bam_port, mbim->port_num, USB_FUNC_MBIM,
			remote_wakeup_allowed);
}

static int mbim_func_suspend(struct usb_function *f, unsigned char options)
+25 −102
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ struct f_ecm_qc {
	struct qc_gether		port;
	u8				ctrl_id, data_id;
	enum transport_type		xport;
	u8				port_num;
	char				ethaddr[14];

	struct usb_ep			*notify;
@@ -78,8 +79,6 @@ struct f_ecm_qc {
	struct data_port		bam_port;
	bool				ecm_mdm_ready_trigger;

	const struct usb_endpoint_descriptor *in_ep_desc_backup;
	const struct usb_endpoint_descriptor *out_ep_desc_backup;
	bool				data_interface_up;
};

@@ -448,72 +447,6 @@ static void ecm_qc_notify(struct f_ecm_qc *ecm)
	ecm_qc_do_notify(ecm);
}

static int ecm_qc_bam_connect(struct f_ecm_qc *dev)
{
	int ret;
	u8 src_connection_idx, dst_connection_idx;
	struct usb_composite_dev *cdev = dev->port.func.config->cdev;
	struct usb_gadget *gadget = cdev->gadget;
	enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
		IPA_P_BAM : A2_P_BAM;
	int port_num;

	port_num = (u_bam_data_func_to_port(USB_FUNC_ECM,
					    ECM_QC_DEFAULT_PORT));
	if (port_num < 0)
		return port_num;
	ret = bam2bam_data_port_select(port_num);
	if (ret) {
		pr_err("ecm_qc port select failed with err:%d\n", ret);
		return ret;
	}

	dev->bam_port.cdev = cdev;
	dev->bam_port.func = &dev->port.func;
	dev->bam_port.in = dev->port.in_ep;
	dev->bam_port.out = dev->port.out_ep;

	/* currently we use the first connection */
	src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
		USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0);
	dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
		PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0);
	if (src_connection_idx < 0 || dst_connection_idx < 0) {
		pr_err("usb_bam_get_connection_idx failed\n");
		return ret;
	}
	ret = bam_data_connect(&dev->bam_port, port_num,
		dev->xport, src_connection_idx, dst_connection_idx,
		USB_FUNC_ECM);
	if (ret) {
		pr_err("bam_data_connect failed: err:%d\n", ret);
		return ret;
	}


	pr_debug("ecm bam connected\n");

	dev->is_open = dev->ecm_mdm_ready_trigger ? true : false;
	ecm_qc_notify(dev);

	return 0;
}

static int ecm_qc_bam_disconnect(struct f_ecm_qc *dev)
{
	int port_num;
	pr_debug("%s: dev:%p. Disconnect BAM.\n", __func__, dev);

	__ecm->ecm_mdm_ready_trigger = false;
	port_num = (u_bam_data_func_to_port(USB_FUNC_ECM,
					    ECM_QC_DEFAULT_PORT));
	if (port_num < 0)
		return port_num;
	bam_data_disconnect(&dev->bam_port, port_num);

	return 0;
}

void *ecm_qc_get_ipa_rx_cb(void)
{
	return ipa_params.ecm_ipa_rx_dp_notify;
@@ -680,7 +613,8 @@ static int ecm_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
			 * path. Only after the BAM data path is disconnected,
			 * we can disconnect the port from the network layer.
			 */
			ecm_qc_bam_disconnect(ecm);
			bam_data_disconnect(&ecm->bam_port, USB_FUNC_ECM,
					ecm->port_num);
			if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA) {
				gether_qc_disconnect_name(&ecm->port, "ecm0");
			} else if (ecm->data_interface_up &&
@@ -723,8 +657,16 @@ static int ecm_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
				}
			}

			if (ecm_qc_bam_connect(ecm))
			ecm->bam_port.cdev = cdev;
			ecm->bam_port.func = &ecm->port.func;
			ecm->bam_port.in = ecm->port.in_ep;
			ecm->bam_port.out = ecm->port.out_ep;
			if (bam_data_connect(&ecm->bam_port, ecm->xport,
				ecm->port_num, USB_FUNC_ECM))
				goto fail;

			ecm->is_open =
				ecm->ecm_mdm_ready_trigger ? true : false;
		}

		ecm->data_interface_up = alt;
@@ -763,7 +705,8 @@ static void ecm_qc_disable(struct usb_function *f)
	DBG(cdev, "ecm deactivated\n");

	if (ecm->port.in_ep->driver_data) {
		ecm_qc_bam_disconnect(ecm);
		bam_data_disconnect(&ecm->bam_port, USB_FUNC_ECM,
				ecm->port_num);
		if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA)
			gether_qc_disconnect_name(&ecm->port, "ecm0");
	} else {
@@ -791,7 +734,6 @@ static void ecm_qc_suspend(struct usb_function *f)
{
	struct f_ecm_qc	*ecm = func_to_ecm_qc(f);
	bool remote_wakeup_allowed;
	int port_num;

	/* Is DATA interface initialized? */
	if (!ecm->data_interface_up) {
@@ -806,24 +748,11 @@ static void ecm_qc_suspend(struct usb_function *f)
			f->config->cdev->gadget->remote_wakeup;

	pr_debug("%s(): remote_wakeup:%d\n:", __func__, remote_wakeup_allowed);
	if (remote_wakeup_allowed) {
		port_num = (u_bam_data_func_to_port(USB_FUNC_ECM,
						    ECM_QC_ACTIVE_PORT));
		if (port_num < 0)
			return;
		bam_data_suspend(port_num);
	} else {
		/*
		 * When remote wakeup is disabled, IPA BAM is disconnected
		 * because it cannot send new data until the USB bus is resumed.
		 * Endpoint descriptors info is saved before it gets reset by
		 * the BAM disconnect API. This lets us restore this info when
		 * the USB bus is resumed.
		 */
		ecm->in_ep_desc_backup  = ecm->bam_port.in->desc;
		ecm->out_ep_desc_backup = ecm->bam_port.out->desc;
		ecm_qc_bam_disconnect(ecm);
	}
	if (!remote_wakeup_allowed)
		__ecm->ecm_mdm_ready_trigger = false;

	bam_data_suspend(&ecm->bam_port, ecm->port_num, USB_FUNC_ECM,
			remote_wakeup_allowed);

	pr_debug("ecm suspended\n");
}
@@ -832,7 +761,6 @@ static void ecm_qc_resume(struct usb_function *f)
{
	struct f_ecm_qc	*ecm = func_to_ecm_qc(f);
	bool remote_wakeup_allowed;
	int port_num;

	if (!ecm->data_interface_up) {
		pr_err("%s(): data interface was not up\n", __func__);
@@ -845,17 +773,12 @@ static void ecm_qc_resume(struct usb_function *f)
		remote_wakeup_allowed =
			f->config->cdev->gadget->remote_wakeup;

	if (remote_wakeup_allowed) {
		port_num = (u_bam_data_func_to_port(USB_FUNC_ECM,
						    ECM_QC_ACTIVE_PORT));
		if (port_num < 0)
			return;
		bam_data_resume(port_num);
	} else {
		/* Restore endpoint descriptors info. */
		ecm->bam_port.in->desc  = ecm->in_ep_desc_backup;
		ecm->bam_port.out->desc = ecm->out_ep_desc_backup;
		ecm_qc_bam_connect(ecm);
	bam_data_resume(&ecm->bam_port, ecm->port_num, USB_FUNC_ECM,
			remote_wakeup_allowed);

	if (!remote_wakeup_allowed) {
		ecm->is_open = ecm->ecm_mdm_ready_trigger ? true : false;
		ecm_qc_notify(ecm);
	}

	pr_debug("ecm resumed\n");
+25 −116
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@
 * Copyright (C) 2008 Nokia Corporation
 * Copyright (C) 2009 Samsung Electronics
 *			Author: Michal Nazarewicz (mina86@mina86.com)
 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2015, 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
@@ -98,9 +98,8 @@ struct f_rndis_qc {
	atomic_t			notify_count;
	struct data_port		bam_port;
	enum transport_type		xport;
	u8				port_num;
	bool				net_ready_trigger;
	const struct usb_endpoint_descriptor *in_ep_desc_backup;
	const struct usb_endpoint_descriptor *out_ep_desc_backup;
};

static struct ipa_usb_init_params rndis_ipa_params;
@@ -416,77 +415,6 @@ static inline void rndis_qc_unlock(atomic_t *excl)
	atomic_dec(excl);
}

/* MSM bam support */
static int rndis_qc_bam_connect(struct f_rndis_qc *dev)
{
	int ret;
	u8 src_connection_idx, dst_connection_idx;
	struct usb_composite_dev *cdev = dev->port.func.config->cdev;
	struct usb_gadget *gadget = cdev->gadget;
	enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
		IPA_P_BAM : A2_P_BAM;
	int port_num;

	dev->bam_port.cdev = cdev;
	dev->bam_port.func = &dev->port.func;
	dev->bam_port.in = dev->port.in_ep;
	dev->bam_port.out = dev->port.out_ep;

	port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS,
					    RNDIS_QC_ACTIVE_PORT));
	if (port_num < 0)
		return port_num;

	ret = bam2bam_data_port_select(port_num);
	if (ret) {
		pr_err("qc rndis bam port setup failed err:%d\n", ret);
		return ret;
	}

	/* currently we use the first connection */
	src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
		USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE, 0);
	dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
		PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0);
	if (src_connection_idx < 0 || dst_connection_idx < 0) {
		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
		return ret;
	}
	if (peer_bam == A2_P_BAM)
		ret = bam_data_connect(&dev->bam_port, port_num,
			USB_GADGET_XPORT_BAM2BAM, src_connection_idx,
			dst_connection_idx, USB_FUNC_RNDIS);
	else {
		ret = bam_data_connect(&dev->bam_port, port_num,
			USB_GADGET_XPORT_BAM2BAM_IPA, src_connection_idx,
			dst_connection_idx, USB_FUNC_RNDIS);
		rndis_qc_open(&dev->port);
	}
	if (ret) {
		pr_err("bam_data_connect failed: err:%d\n",
				ret);
		return ret;
	}

	pr_info("rndis bam connected\n");

	return 0;
}

static int rndis_qc_bam_disconnect(struct f_rndis_qc *dev)
{
	int port_num;
	pr_debug("dev:%p. %s Disconnect BAM.\n", dev, __func__);

	port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS,
					    RNDIS_QC_ACTIVE_PORT));
	if (port_num < 0)
		return port_num;
	bam_data_disconnect(&dev->bam_port, port_num);

	return 0;
}

/*-------------------------------------------------------------------------*/

static struct sk_buff *rndis_qc_add_header(struct qc_gether *port,
@@ -730,7 +658,8 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
			 * path. Only after the BAM data path is disconnected,
			 * we can disconnect the port from the network layer.
			 */
			rndis_qc_bam_disconnect(rndis);
			bam_data_disconnect(&rndis->bam_port, USB_FUNC_RNDIS,
					rndis->port_num);

			if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA)
				gether_qc_disconnect_name(&rndis->port,
@@ -776,15 +705,23 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
		 */
		rndis->port.cdc_filter = 0;

		if (rndis_qc_bam_connect(rndis))
		rndis->bam_port.cdev = cdev;
		rndis->bam_port.func = &rndis->port.func;
		rndis->bam_port.in = rndis->port.in_ep;
		rndis->bam_port.out = rndis->port.out_ep;

		if (bam_data_connect(&rndis->bam_port, rndis->xport,
					rndis->port_num, USB_FUNC_RNDIS))
			goto fail;

		DBG(cdev, "RNDIS RX/TX early activation ...\n");
		if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA)
		if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA) {
			net = gether_qc_connect_name(&rndis->port, "rndis0",
				false);
		else
		} else {
			rndis_qc_open(&rndis->port);
			net = gether_qc_get_net("rndis0");
		}
		if (IS_ERR(net))
			return PTR_ERR(net);

@@ -809,7 +746,7 @@ static void rndis_qc_disable(struct usb_function *f)
	pr_info("rndis deactivated\n");

	rndis_uninit(rndis->config);
	rndis_qc_bam_disconnect(rndis);
	bam_data_disconnect(&rndis->bam_port, USB_FUNC_RNDIS, rndis->port_num);
	if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA)
		gether_qc_disconnect_name(&rndis->port, "rndis0");

@@ -826,7 +763,6 @@ static void rndis_qc_suspend(struct usb_function *f)
{
	struct f_rndis_qc	*rndis = func_to_rndis_qc(f);
	bool remote_wakeup_allowed;
	int port_num;

	if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
		remote_wakeup_allowed = f->func_wakeup_allowed;
@@ -836,13 +772,7 @@ static void rndis_qc_suspend(struct usb_function *f)
	pr_info("%s(): start rndis suspend: remote_wakeup_allowed:%d\n:",
					__func__, remote_wakeup_allowed);

	if (remote_wakeup_allowed) {
		port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS,
					    RNDIS_QC_ACTIVE_PORT));
		if (port_num < 0)
			return;
		bam_data_suspend(port_num);
	} else {
	if (!remote_wakeup_allowed) {
		/* This is required as Linux host side RNDIS driver doesn't
		 * send RNDIS_MESSAGE_PACKET_FILTER before suspending USB bus.
		 * Hence we perform same operations explicitly here for Linux
@@ -850,26 +780,11 @@ static void rndis_qc_suspend(struct usb_function *f)
		 * already updated due to receiving of PACKET_FILTER.
		 */
		rndis_flow_control(rndis->config, true);

		/*
		 * When remote wakeup is disabled, IPA BAM is disconnected
		 * because it cannot send new data until the USB bus is resumed.
		 * Endpoint descriptors info is saved before it gets reset by
		 * the BAM disconnect API. This lets us restore this info when
		 * the USB bus is resumed.
		 */
		if (rndis->bam_port.in->desc)
			rndis->in_ep_desc_backup  = rndis->bam_port.in->desc;

		if (rndis->bam_port.out->desc)
			rndis->out_ep_desc_backup = rndis->bam_port.out->desc;

		pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p",
			rndis->in_ep_desc_backup, rndis->out_ep_desc_backup);
		pr_debug("%s(): Disconnecting\n", __func__);
		rndis_qc_bam_disconnect(rndis);
	}

	bam_data_suspend(&rndis->bam_port, rndis->port_num, USB_FUNC_RNDIS,
			remote_wakeup_allowed);
	pr_debug("rndis suspended\n");
}

@@ -877,7 +792,6 @@ static void rndis_qc_resume(struct usb_function *f)
{
	struct f_rndis_qc	*rndis = func_to_rndis_qc(f);
	bool remote_wakeup_allowed;
	int port_num;

	pr_debug("%s: rndis resumed\n", __func__);

@@ -892,17 +806,12 @@ static void rndis_qc_resume(struct usb_function *f)
	else
		remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;

	if (remote_wakeup_allowed) {
		port_num = (u_bam_data_func_to_port(USB_FUNC_RNDIS,
						    RNDIS_QC_ACTIVE_PORT));
		if (port_num < 0)
			return;
		bam_data_resume(port_num);
	} else {
		/* Restore endpoint descriptors info. */
		rndis->bam_port.in->desc  = rndis->in_ep_desc_backup;
		rndis->bam_port.out->desc = rndis->out_ep_desc_backup;
		rndis_qc_bam_connect(rndis);
	bam_data_resume(&rndis->bam_port, rndis->port_num, USB_FUNC_RNDIS,
			remote_wakeup_allowed);

	if (!remote_wakeup_allowed) {
		if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA)
			rndis_qc_open(&rndis->port);
		/*
		 * Linux Host doesn't sends RNDIS_MSG_INIT or non-zero value
		 * set with RNDIS_MESSAGE_PACKET_FILTER after performing bus
+107 −28
Original line number Diff line number Diff line
@@ -1362,20 +1362,23 @@ static void bam_data_free_reqs(struct bam_data_port *port)
	}
}

void bam_data_disconnect(struct data_port *gr, u8 port_num)
void bam_data_disconnect(struct data_port *gr, enum function_type func,
		u8 dev_port_num)
{
	struct bam_data_port *port;
	struct bam_data_ch_info	*d;
	struct sk_buff *skb = NULL;
	unsigned long flags;
	int port_num;

	pr_debug("dev:%p port number:%d\n", gr, port_num);

	if (port_num >= n_bam2bam_data_ports) {
	port_num = u_bam_data_func_to_port(func, dev_port_num);
	if (port_num < 0 || port_num >= n_bam2bam_data_ports) {
		pr_err("invalid bam2bam portno#%d\n", port_num);
		return;
	}

	pr_debug("dev:%p port number:%d\n", gr, port_num);

	if (!gr) {
		pr_err("data port is null\n");
		return;
@@ -1479,26 +1482,49 @@ void bam_data_disconnect(struct data_port *gr, u8 port_num)
	spin_unlock_irqrestore(&port->port_lock, flags);
}

int bam_data_connect(struct data_port *gr, u8 port_num,
	enum transport_type trans, u8 src_connection_idx,
	u8 dst_connection_idx, enum function_type func)
int bam_data_connect(struct data_port *gr, enum transport_type trans,
		u8 dev_port_num, enum function_type func)
{
	struct bam_data_port	*port;
	struct bam_data_ch_info	*d;
	int			ret;
	int			ret, port_num;
	unsigned long		flags;

	pr_debug("dev:%p port#%d\n", gr, port_num);
	if (port_num >= n_bam2bam_data_ports) {
		pr_err("invalid portno#%d\n", port_num);
		return -ENODEV;
	}
	enum peer_bam		bam_name;
	u8			src_connection_idx, dst_connection_idx;

	if (!gr) {
		pr_err("data port is null\n");
		return -ENODEV;
	}

	port_num = u_bam_data_func_to_port(func, dev_port_num);
	if (port_num < 0 || port_num >= n_bam2bam_data_ports) {
		pr_err("invalid portno#%d\n", port_num);
		return -EINVAL;
	}

	pr_debug("dev:%p port#%d\n", gr, port_num);

	bam_name = (trans == USB_GADGET_XPORT_BAM2BAM_IPA) ?
							IPA_P_BAM : A2_P_BAM;

	ret = bam2bam_data_port_select(port_num);
	if (ret) {
		pr_err("mbim port select failed err: %d\n", ret);
		return ret;
	}

	src_connection_idx = usb_bam_get_connection_idx(gr->cdev->gadget->name,
			bam_name, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE,
			dev_port_num);
	dst_connection_idx = usb_bam_get_connection_idx(gr->cdev->gadget->name,
			bam_name, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE,
			dev_port_num);
	if (src_connection_idx < 0 || dst_connection_idx < 0) {
		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
		return ret;
	}

	port = bam2bam_data_ports[port_num];

	spin_lock_irqsave(&port->port_lock, flags);
@@ -1815,40 +1841,93 @@ static void bam_data_stop(void *param, enum usb_bam_pipe_dir dir)
	}
}

void bam_data_suspend(u8 port_num)
void bam_data_suspend(struct data_port *port_usb, u8 dev_port_num,
		enum function_type func, bool remote_wakeup_enabled)
{
	struct bam_data_port *port;
	unsigned long flags;
	int port_num;

	port_num = u_bam_data_func_to_port(func, dev_port_num);
	if (port_num < 0 || port_num >= n_bam2bam_data_ports) {
		pr_err("invalid bam2bam portno#%d\n", port_num);
		return;
	}

	pr_debug("%s: suspended port %d\n", __func__, port_num);

	port = bam2bam_data_ports[port_num];
	if (port) {
	if (!port) {
		pr_err("%s(): Port is NULL.\n", __func__);
		return;
	}

	/* suspend with remote wakeup disabled */
	if (!remote_wakeup_enabled) {
		/*
		 * When remote wakeup is disabled, IPA BAM is disconnected
		 * because it cannot send new data until the USB bus is resumed.
		 * Endpoint descriptors info is saved before it gets reset by
		 * the BAM disconnect API. This lets us restore this info when
		 * the USB bus is resumed.
		 */
		port_usb->in_ep_desc_backup = port_usb->in->desc;
		port_usb->out_ep_desc_backup = port_usb->out->desc;

		pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p",
			port_usb->in_ep_desc_backup,
			port_usb->out_ep_desc_backup);

		bam_data_disconnect(port_usb, func, dev_port_num);
		return;
	}

	spin_lock_irqsave(&port->port_lock, flags);
	port->last_event = U_BAM_DATA_SUSPEND_E;
	queue_work(bam_data_wq, &port->suspend_w);
	spin_unlock_irqrestore(&port->port_lock, flags);
	} else {
		pr_err("%s(): Port is NULL.\n", __func__);
	}
}

void bam_data_resume(u8 port_num)
void bam_data_resume(struct data_port *port_usb, u8 dev_port_num,
		enum function_type func, bool remote_wakeup_enabled)
{
	struct bam_data_port *port;
	unsigned long flags;
	int port_num;

	port_num = u_bam_data_func_to_port(func, dev_port_num);
	if (port_num < 0 || port_num >= n_bam2bam_data_ports) {
		pr_err("invalid bam2bam portno#%d\n", port_num);
		return;
	}

	pr_debug("%s: resumed port %d\n", __func__, port_num);

	port = bam2bam_data_ports[port_num];
	if (port) {
	if (!port) {
		pr_err("%s(): Port is NULL.\n", __func__);
		return;
	}

	/* resume with remote wakeup disabled */
	if (!remote_wakeup_enabled) {
		/* Restore endpoint descriptors info. */
		port_usb->in->desc = port_usb->in_ep_desc_backup;
		port_usb->out->desc = port_usb->out_ep_desc_backup;

		pr_debug("in_ep_desc_backup = %p, out_ep_desc_backup = %p",
			port_usb->in_ep_desc_backup,
			port_usb->out_ep_desc_backup);

		bam_data_connect(port_usb, port->data_ch.trans,
			dev_port_num, func);
		return;
	}

	spin_lock_irqsave(&port->port_lock, flags);
	port->last_event = U_BAM_DATA_RESUME_E;
	queue_work(bam_data_wq, &port->resume_w);
	spin_unlock_irqrestore(&port->port_lock, flags);
	} else {
		pr_err("%s(): Port is NULL.\n", __func__);
	}
}

void bam_data_flush_workqueue(void)
+18 −14
Original line number Diff line number Diff line
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2015, 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
@@ -33,23 +33,27 @@ struct data_port {
	struct usb_ep				*out;
	int					ipa_consumer_ep;
	int					ipa_producer_ep;
	const struct usb_endpoint_descriptor	*in_ep_desc_backup;
	const struct usb_endpoint_descriptor	*out_ep_desc_backup;
};

int bam2bam_data_port_select(int portno);

void bam_data_disconnect(struct data_port *gr, u8 port_num);
void bam_data_disconnect(struct data_port *gr, enum function_type func,
		u8 dev_port_num);

int bam_data_connect(struct data_port *gr, u8 port_num,
	enum transport_type trans, u8 src_connection_idx,
	u8 dst_connection_idx, enum function_type func);
int bam_data_connect(struct data_port *gr, enum transport_type trans,
		u8 dev_port_num, enum function_type func);

int bam_data_setup(enum function_type func, unsigned int no_bam2bam_port);

void bam_data_flush_workqueue(void);

void bam_data_suspend(u8 port_num);
void bam_data_suspend(struct data_port *port_usb, u8 dev_port_num,
		enum function_type func, bool remote_wakeup_enabled);

void bam_data_resume(u8 port_num);
void bam_data_resume(struct data_port *port_usb, u8 dev_port_num,
		enum function_type func, bool remote_wakeup_enabled);

void u_bam_data_set_dl_max_xfer_size(u32 dl_max_transfer_size);