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

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

Merge "USB: gadget: IPA disconnect on USB suspend when remote wakeup is disabled"

parents 8b65073e c32314b3
Loading
Loading
Loading
Loading
+8 −9
Original line number Diff line number Diff line
@@ -1633,7 +1633,7 @@ static int ci13xxx_wakeup(struct usb_gadget *_gadget)
	trace();

	spin_lock_irqsave(udc->lock, flags);
	if (!udc->remote_wakeup) {
	if (!udc->gadget.remote_wakeup) {
		ret = -EOPNOTSUPP;
		dbg_trace("remote wakeup feature is not enabled\n");
		goto out;
@@ -1684,7 +1684,7 @@ static void usb_do_remote_wakeup(struct work_struct *w)
	 * if wakeup conditions are still met.
	 */
	spin_lock_irqsave(udc->lock, flags);
	do_wake = udc->suspended && udc->remote_wakeup;
	do_wake = udc->suspended && udc->gadget.remote_wakeup;
	spin_unlock_irqrestore(udc->lock, flags);

	if (do_wake)
@@ -2026,8 +2026,7 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)

	/* Remote Wakeup */
	if (udc->suspended) {
		if (!udc->remote_wakeup) {

		if (!udc->gadget.remote_wakeup) {
			mReq->req.status = -EAGAIN;

			dev_dbg(mEp->device,
@@ -2404,7 +2403,7 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)

	spin_lock_irqsave(udc->lock, flags);
	udc->gadget.speed = USB_SPEED_UNKNOWN;
	udc->remote_wakeup = 0;
	udc->gadget.remote_wakeup = 0;
	udc->suspended = 0;
	udc->configured = 0;
	spin_unlock_irqrestore(udc->lock, flags);
@@ -2587,7 +2586,7 @@ __acquires(mEp->lock)
			req->length = 1;
		} else {
			/* Assume that device is bus powered for now. */
			*((u16 *)req->buf) = _udc->remote_wakeup << 1;
			*((u16 *)req->buf) = _udc->gadget.remote_wakeup << 1;
		}
		/* TODO: D1 - Remote Wakeup; D0 - Self Powered */
		retval = 0;
@@ -2857,7 +2856,7 @@ __acquires(udc->lock)
					USB_DEVICE_REMOTE_WAKEUP) {
				if (req.wLength != 0)
					break;
				udc->remote_wakeup = 0;
				udc->gadget.remote_wakeup = 0;
				err = isr_setup_status_phase(udc);
			} else {
				goto delegate;
@@ -2909,7 +2908,7 @@ __acquires(udc->lock)
					break;
				switch (le16_to_cpu(req.wValue)) {
				case USB_DEVICE_REMOTE_WAKEUP:
					udc->remote_wakeup = 1;
					udc->gadget.remote_wakeup = 1;
					err = isr_setup_status_phase(udc);
					break;
				case USB_DEVICE_B_HNP_ENABLE:
@@ -3310,7 +3309,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,

	if (udc->suspended) {
		/* Remote Wakeup */
		if (!udc->remote_wakeup) {
		if (!udc->gadget.remote_wakeup) {

			dev_dbg(mEp->device,
					"%s: queue failed (suspend)."
+0 −2
Original line number Diff line number Diff line
@@ -167,8 +167,6 @@ struct ci13xxx {
	u32                        ep0_dir;    /* ep0 direction */
#define ep0out ci13xxx_ep[0]
#define ep0in  ci13xxx_ep[hw_ep_max / 2]
	u8                         remote_wakeup; /* Is remote wakeup feature
							enabled by the host? */
	u8                         suspended;  /* suspended by the host */
	u8                         configured;  /* is device configured */
	u8                         test_mode;  /* the selected test mode */
+33 −6
Original line number Diff line number Diff line
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, 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
@@ -90,6 +90,9 @@ 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;
	u8				data_alt_int;

@@ -720,9 +723,7 @@ static int mbim_bam_connect(struct f_mbim *dev)

static int mbim_bam_disconnect(struct f_mbim *dev)
{
	pr_info("dev:%p port:%d. Do nothing.\n",
			dev, dev->port_num);

	pr_info("%s - dev:%p port:%d\n", __func__, dev, dev->port_num);
	bam_data_disconnect(&dev->bam_port, dev->port_num);

	return 0;
@@ -1394,14 +1395,40 @@ static void mbim_disable(struct usb_function *f)

static void mbim_suspend(struct usb_function *f)
{
	struct f_mbim	*mbim = func_to_mbim(f);

	pr_info("mbim suspended\n");

	if (mbim->cdev->gadget->remote_wakeup) {
		bam_data_suspend(MBIM_ACTIVE_PORT);
	} 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.
		 */
		mbim->in_ep_desc_backup  = mbim->bam_port.in->desc;
		mbim->out_ep_desc_backup = mbim->bam_port.out->desc;
		mbim_bam_disconnect(mbim);
	}
}

static void mbim_resume(struct usb_function *f)
{
	struct f_mbim	*mbim = func_to_mbim(f);

	pr_info("mbim resumed\n");

	if (mbim->cdev->gadget->remote_wakeup) {
		bam_data_resume(MBIM_ACTIVE_PORT);
	} 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;
		mbim_bam_connect(mbim);
	}
}

/*---------------------- function driver setup/binding ---------------------*/
+36 −9
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
 *
 * Copyright (C) 2003-2005,2008 David Brownell
 * Copyright (C) 2008 Nokia Corporation
 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2014, 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
@@ -76,6 +76,9 @@ struct f_ecm_qc {
	u8				notify_state;
	bool				is_open;
	struct data_port		bam_port;

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

static struct ecm_ipa_params ipa_params;
@@ -407,10 +410,11 @@ static int ecm_qc_bam_connect(struct f_ecm_qc *dev)
	if (ret) {
		pr_err("bam_data_connect failed: err:%d\n", ret);
		return ret;
	} else {
		pr_debug("ecm bam connected\n");
	}


	pr_debug("ecm bam connected\n");

	dev->is_open = true;
	ecm_qc_notify(dev);

@@ -419,8 +423,7 @@ static int ecm_qc_bam_connect(struct f_ecm_qc *dev)

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

	pr_debug("%s: dev:%p. Disconnect BAM.\n", __func__, dev);
	bam_data_disconnect(&dev->bam_port, 0);

	return 0;
@@ -677,16 +680,40 @@ static void ecm_qc_disable(struct usb_function *f)

static void ecm_qc_suspend(struct usb_function *f)
{
	pr_debug("ecm suspended\n");
	struct f_ecm_qc	*ecm = func_to_ecm_qc(f);

	if (f->config->cdev->gadget->remote_wakeup) {
		bam_data_suspend(ECM_QC_ACTIVE_PORT);
	} 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);
	}

	pr_debug("ecm suspended\n");
}

static void ecm_qc_resume(struct usb_function *f)
{
	pr_debug("ecm resumed\n");
	struct f_ecm_qc	*ecm = func_to_ecm_qc(f);

	if (f->config->cdev->gadget->remote_wakeup) {
		bam_data_resume(ECM_QC_ACTIVE_PORT);
	} 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);
	}

	pr_debug("ecm resumed\n");
}

/*-------------------------------------------------------------------------*/
+37 −11
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ static struct work_struct *rndis_disconn_w;
static bool is_ipa_rndis_net_on;

struct bam_data_port {
	bool                            is_connected;
	unsigned			port_num;
	unsigned int                    ref_count;
	struct data_port		*port_usb;
@@ -200,6 +201,11 @@ static void bam2bam_data_disconnect_work(struct work_struct *w)
	struct bam_data_ch_info *d = &port->data_ch;
	int ret;

	if (!port->is_connected) {
		pr_info("%s: Already disconnected. Bailing out.\n", __func__);
		return;
	}

	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
		if (d->func_type == USB_FUNC_ECM)
			ecm_ipa_disconnect(d->ipa_params.priv);
@@ -254,6 +260,11 @@ static void bam2bam_data_connect_work(struct work_struct *w)

	pr_debug("%s: Connect workqueue started", __func__);

	if (port->is_connected) {
		pr_info("%s: Already connected. Bailing out.\n", __func__);
		return;
	}

	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
		if (d->func_type == USB_FUNC_MBIM) {
			ret = teth_bridge_init(&usb_notify_cb, &priv,
@@ -488,6 +499,7 @@ static int bam2bam_data_port_alloc(int portno)

	port->port_num  = portno;
	port->ref_count = 1;
	port->is_connected = false;

	INIT_WORK(&port->connect_w, bam2bam_data_connect_work);
	INIT_WORK(&port->disconnect_w, bam2bam_data_disconnect_work);
@@ -562,15 +574,14 @@ void bam_data_disconnect(struct data_port *gr, u8 port_num)
	}

	d = &port->data_ch;
	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)
	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
		queue_work(bam_data_wq, &port->disconnect_w);
	else {
		if (usb_bam_client_ready(false)) {
	} else {
		if (usb_bam_client_ready(false))
			pr_err("%s: usb_bam_client_ready failed\n",
				__func__);
	}
}
}

int bam_data_connect(struct data_port *gr, u8 port_num,
	enum transport_type trans, u8 src_connection_idx,
@@ -593,13 +604,12 @@ int bam_data_connect(struct data_port *gr, u8 port_num,
	}

	port = bam2bam_data_ports[port_num];

	d = &port->data_ch;

	ret = usb_ep_enable(gr->in);
	if (ret) {
		pr_err("usb_ep_enable failed eptype:IN ep:%p", gr->in);
		return ret;
		goto exit;
	}
	gr->in->driver_data = port;

@@ -607,7 +617,7 @@ int bam_data_connect(struct data_port *gr, u8 port_num,
	if (ret) {
		pr_err("usb_ep_enable failed eptype:OUT ep:%p", gr->out);
		gr->in->driver_data = 0;
		return ret;
		goto exit;
	}
	gr->out->driver_data = port;

@@ -629,11 +639,15 @@ int bam_data_connect(struct data_port *gr, u8 port_num,
	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA && d->func_type ==
		USB_FUNC_RNDIS) {
			rndis_conn_w = &port->connect_w;
			return 0;
			ret = 0;
			goto exit;
	}

	queue_work(bam_data_wq, &port->connect_w);
	ret = 0;

	return 0;
exit:
	return ret;
}

int bam_data_destroy(unsigned int no_bam2bam_port)
@@ -778,10 +792,16 @@ static void bam2bam_data_suspend_work(struct work_struct *w)

	pr_debug("%s: suspend work started\n", __func__);

	if (!port->is_connected) {
		pr_info("%s: Port is disconnected. Bailing out.\n", __func__);
		return;
	}

	ret = usb_bam_register_wake_cb(d->dst_connection_idx,
					bam_data_wake_cb, port);
	if (ret) {
		pr_err("%s(): pipe is NULL.\n", __func__);
		pr_err("%s(): Failed to register BAM wake callback.\n",
			__func__);
		return;
	}

@@ -802,9 +822,15 @@ static void bam2bam_data_resume_work(struct work_struct *w)

	pr_debug("%s: resume work started\n", __func__);

	if (!port->is_connected) {
		pr_info("%s: Port is disconnected. Bailing out.\n", __func__);
		return;
	}

	ret = usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
	if (ret) {
		pr_err("%s(): pipe is NULL.\n", __func__);
		pr_err("%s(): Failed to un-register BAM wake callback.\n",
			__func__);
		return;
	}

Loading