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

Commit 5a8d1e95 authored by Nadine Toledano's avatar Nadine Toledano
Browse files

usb: gadget: Fix race condition in enable\disable Rmnet device



This fixes race condition in fast disable and re-enable Rmnet device.
Now the mechanism is similar to the connect\disconnect mechanism
in u_bam_data.

CRs-Fixed: 524776
Change-Id: Idfbb5904be05f66ea404c1a806e4d224ecd553df
Signed-off-by: default avatarNadine Toledano <nadinet@codeaurora.org>
parent 07ca70b0
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -595,9 +595,12 @@ static int gport_rmnet_disconnect(struct f_rmnet *dev)
static void frmnet_unbind(struct usb_configuration *c, struct usb_function *f)
{
	struct f_rmnet *dev = func_to_rmnet(f);
	enum transport_type	dxport = rmnet_ports[dev->port_num].data_xport;

	pr_debug("%s: portno:%d\n", __func__, dev->port_num);

	if ((dxport == USB_GADGET_XPORT_BAM2BAM ||
		 dxport == USB_GADGET_XPORT_BAM2BAM_IPA))
			gbam_destroy(dev->port_num);
	if (gadget_is_superspeed(c->cdev->gadget))
		usb_free_descriptors(f->ss_descriptors);
	if (gadget_is_dualspeed(c->cdev->gadget))
+16 −38
Original line number Diff line number Diff line
@@ -967,7 +967,6 @@ static int gbam_peer_reset_cb(void *param)
	struct f_rmnet		*dev;
	struct usb_gadget *gadget;
	int ret;
	bool reenable_eps = false;

	dev = port_to_rmnet(port->gr);
	d = &port->data_ch;
@@ -975,18 +974,6 @@ static int gbam_peer_reset_cb(void *param)
	gadget = dev->cdev->gadget;

	pr_debug("%s: reset by peer\n", __func__);

	/* Disable the relevant EPs if currently EPs are enabled */
	if (port->port_usb && port->port_usb->in &&
	  port->port_usb->in->driver_data) {
		usb_ep_disable(port->port_usb->out);
		usb_ep_disable(port->port_usb->in);

		port->port_usb->in->driver_data = NULL;
		port->port_usb->out->driver_data = NULL;
		reenable_eps = true;
	}

	/* Disable BAM */
	msm_hw_bam_disable(1);

@@ -994,36 +981,12 @@ static int gbam_peer_reset_cb(void *param)
	ret = usb_bam_a2_reset(0);
	if (ret) {
		pr_err("%s: BAM reset failed %d\n", __func__, ret);
		goto reenable_eps;
		return ret;
	}

	/* Enable BAM */
	msm_hw_bam_disable(0);

reenable_eps:
	/* Re-Enable the relevant EPs, if EPs were originally enabled */
	if (reenable_eps) {
		ret = usb_ep_enable(port->port_usb->in);
		if (ret) {
			pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
				__func__, port->port_usb->in);
			return ret;
		}
		port->port_usb->in->driver_data = port;

		ret = usb_ep_enable(port->port_usb->out);
		if (ret) {
			pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
				__func__, port->port_usb->out);
			port->port_usb->in->driver_data = 0;
			return ret;
		}
		port->port_usb->out->driver_data = port;

		gbam_start_endless_rx(port);
		gbam_start_endless_tx(port);
	}

	/* Unregister the peer reset callback */
	if (d->trans == USB_GADGET_XPORT_BAM2BAM && port->port_num == 0)
		usb_bam_register_peer_reset_cb(NULL, NULL);
@@ -1465,6 +1428,17 @@ int gbam_connect(struct grmnet *gr, u8 port_num,
	return 0;
}

int gbam_destroy(unsigned int no_bam2bam_port)
{
	pr_debug("bam_destroy: Freeing ports\n");
	gbam2bam_port_free(no_bam2bam_port);
	if (gbam_wq)
		destroy_workqueue(gbam_wq);
	gbam_wq = NULL;

	return 0;
}

int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port)
{
	int	i;
@@ -1479,6 +1453,10 @@ int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port)
				__func__, no_bam_port, no_bam2bam_port);
		return -EINVAL;
	}
	if (gbam_wq) {
		pr_debug("bam is already setup");
		return 0;
	}

	gbam_wq = alloc_workqueue("k_gbam", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
	if (!gbam_wq) {
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ void gbam_disconnect(struct grmnet *gr, u8 port_num,
	enum transport_type trans);
void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
int gbam_destroy(unsigned int no_bam2bam_port);
int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
int gsmd_ctrl_setup(enum ctrl_client client_num, unsigned int count,