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

Commit bf885ace authored by Bar Weiner's avatar Bar Weiner
Browse files

usb: gadget: Perform usb_ep_disable in workqueue



bam_data_disconnect can be called in interrupt context,
as a result of suspend event. During an interrupt
handling, usb gadget lock is held, so when trying
to disable an endpoint a deadlock happens.
This fix moves the disabling of the data endpoints to
a deferred context, which prevents the deadlock.

Change-Id: I4caf0740842760630aac6649b7fe7ed93a940e7a
Signed-off-by: default avatarBar Weiner <bweiner@codeaurora.org>
parent 8c750d7e
Loading
Loading
Loading
Loading
+43 −31
Original line number Diff line number Diff line
@@ -531,6 +531,46 @@ static int bam_data_peer_reset_cb(void *param)
	return 0;
}

static void disable_data_ep(struct bam_data_port *port)
{
	struct bam_data_ch_info *d = &port->data_ch;

	if (!port->port_usb)
		return;

	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
		port->port_usb->ipa_consumer_ep = -1;
		port->port_usb->ipa_producer_ep = -1;
	}

	if (port->port_usb->in && port->port_usb->in->driver_data) {
		/* disable endpoints */
		usb_ep_disable(port->port_usb->out);
		usb_ep_disable(port->port_usb->in);

		/*
		 * Set endless flag to false as USB Endpoint
		 * is already disable.
		 */
		if (d->trans == USB_GADGET_XPORT_BAM2BAM ||
			d->trans == USB_GADGET_XPORT_BAM2BAM_IPA ||
			d->trans == USB_GADGET_XPORT_BAM) {

			if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
				port->port_usb->in->endless = false;

			if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
				port->port_usb->out->endless = false;
		}

		port->port_usb->in->driver_data = NULL;
		port->port_usb->out->driver_data = NULL;

		port->port_usb = NULL;
	}
}


static void bam2bam_data_disconnect_work(struct work_struct *w)
{
	struct bam_data_port *port =
@@ -544,6 +584,8 @@ static void bam2bam_data_disconnect_work(struct work_struct *w)
		return;
	}

	disable_data_ep(port);

	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
		if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
			priv = d->ipa_params.priv;
@@ -984,41 +1026,11 @@ void bam_data_disconnect(struct data_port *gr, u8 port_num)
	}

	d = &port->data_ch;
	if (port->port_usb) {
		if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
			port->port_usb->ipa_consumer_ep = -1;
			port->port_usb->ipa_producer_ep = -1;
		}
		if (port->port_usb->in && port->port_usb->in->driver_data) {
			/* disable endpoints */
			usb_ep_disable(port->port_usb->out);
			usb_ep_disable(port->port_usb->in);

			/*
			 * Set endless flag to false as USB Endpoint
			 * is already disable.
			 */
			if (d->trans == USB_GADGET_XPORT_BAM2BAM ||
				d->trans == USB_GADGET_XPORT_BAM2BAM_IPA ||
				d->trans == USB_GADGET_XPORT_BAM) {

				if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
					port->port_usb->in->endless = false;

				if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
					port->port_usb->out->endless = false;
			}

			port->port_usb->in->driver_data = NULL;
			port->port_usb->out->driver_data = NULL;

			port->port_usb = NULL;
		}
	}

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