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

Commit 55982aa4 authored by Vijayavardhan Vennapusa's avatar Vijayavardhan Vennapusa
Browse files

USB: gadget: u_bam: Free usb requests during disconnect



Currently USB requests are allocated during connect work for starting
endless TX and RX in BAM2BAM over IPA. But these requests are not freed
during disconnect which leads to memory leak and could result in memory
allocation failure in function drivers during next connect. Hence free USB
requests allocated during disconnect to fix memleakissue and also move
allocation of RX/TX usb requests to gbam_connect to avoid crashes due
to NULL pointer dereference.

CRs-Fixed: 840264
Change-Id: Ia4f1d28277a22741defb03086320ffa3895ddfae
Signed-off-by: default avatarVijayavardhan Vennapusa <vvreddy@codeaurora.org>
parent 260b1b32
Loading
Loading
Loading
Loading
+69 −30
Original line number Diff line number Diff line
@@ -1296,34 +1296,6 @@ static void gbam2bam_connect_work(struct work_struct *w)
	}
	d = &port->data_ch;

	d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_ATOMIC);
	if (!d->rx_req) {
		spin_unlock(&port->port_lock_dl);
		spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
		spin_unlock_irqrestore(&port->port_lock, flags);
		pr_err("%s: out of memory\n", __func__);
		return;
	}

	d->rx_req->context = port;
	d->rx_req->complete = gbam_endless_rx_complete;
	d->rx_req->length = 0;
	d->rx_req->no_interrupt = 1;

	d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_ATOMIC);
	spin_unlock(&port->port_lock_dl);
	spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
	if (!d->tx_req) {
		pr_err("%s: out of memory\n", __func__);
		spin_unlock_irqrestore(&port->port_lock, flags);
		return;
	}

	d->tx_req->context = port;
	d->tx_req->complete = gbam_endless_tx_complete;
	d->tx_req->length = 0;
	d->tx_req->no_interrupt = 1;

	/*
	 * Unlock the port here and not at the end of this work,
	 * because we do not want to activate usb_bam, ipa and
@@ -1332,6 +1304,8 @@ static void gbam2bam_connect_work(struct work_struct *w)
	 * and event functions (as bam_data_connect) will not influance
	 * while lower layers connect pipes, etc.
	*/
	spin_unlock(&port->port_lock_dl);
	spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
	spin_unlock_irqrestore(&port->port_lock, flags);

	d->ipa_params.usb_connection_speed = gadget->speed;
@@ -1467,6 +1441,13 @@ static void gbam2bam_connect_work(struct work_struct *w)
			return;
		}
	}

	spin_lock_irqsave(&port->port_lock, flags);
	if (!port->port_usb) {
		pr_debug("%s: usb cable is disconnected\n", __func__);
		spin_unlock_irqrestore(&port->port_lock, flags);
		return;
	}
	/* Update BAM specific attributes */
	if (gadget_is_dwc3(gadget)) {
		sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | MSM_PRODUCER |
@@ -1486,6 +1467,7 @@ static void gbam2bam_connect_work(struct work_struct *w)
				MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
	}
	d->tx_req->udc_priv = sps_params;
	spin_unlock_irqrestore(&port->port_lock, flags);

	/* queue in & out requests */
	if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM) {
@@ -1964,11 +1946,15 @@ static inline void gbam_debugfs_remove(void) {}
void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
{
	struct gbam_port	*port;
	unsigned long		flags, flags_ul;
	unsigned long		flags, flags_ul, flags_dl;
	struct bam_ch_info	*d;

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

	if (trans == USB_GADGET_XPORT_BAM2BAM) {
		pr_err("%s: invalid xport#%d\n", __func__, trans);
		return;
	}
	if (trans == USB_GADGET_XPORT_BAM &&
		port_num >= n_bam_ports) {
		pr_err("%s: invalid bam portno#%d\n",
@@ -2030,9 +2016,26 @@ void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
	spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);

	/* disable endpoints */
	if (gr->out)
	if (gr->out) {
		usb_ep_disable(gr->out);
		if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
			spin_lock_irqsave(&port->port_lock_ul, flags_ul);
			if (d->rx_req) {
				usb_ep_free_request(gr->out, d->rx_req);
				d->rx_req = NULL;
			}
			spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
		}
	}
	usb_ep_disable(gr->in);
	if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
		spin_lock_irqsave(&port->port_lock_dl, flags_dl);
		if (d->tx_req) {
			usb_ep_free_request(gr->in, d->tx_req);
			d->tx_req = NULL;
		}
		spin_unlock_irqrestore(&port->port_lock_dl, flags_dl);
	}

	/*
	 * Set endless flag to false as USB Endpoint is already
@@ -2122,6 +2125,42 @@ int gbam_connect(struct grmnet *gr, u8 port_num,
	port->port_usb = gr;
	port->gadget = port->port_usb->gadget;

	if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
		d->rx_req = usb_ep_alloc_request(port->port_usb->out,
								GFP_ATOMIC);
		if (!d->rx_req) {
			pr_err("%s: RX request allocation failed\n", __func__);
			d->rx_req = NULL;
			spin_unlock(&port->port_lock_dl);
			spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
			spin_unlock_irqrestore(&port->port_lock, flags);
			return -ENOMEM;
		}

		d->rx_req->context = port;
		d->rx_req->complete = gbam_endless_rx_complete;
		d->rx_req->length = 0;
		d->rx_req->no_interrupt = 1;

		d->tx_req = usb_ep_alloc_request(port->port_usb->in,
								GFP_ATOMIC);
		if (!d->tx_req) {
			pr_err("%s: TX request allocation failed\n", __func__);
			d->tx_req = NULL;
			usb_ep_free_request(port->port_usb->out, d->rx_req);
			d->rx_req = NULL;
			spin_unlock(&port->port_lock_dl);
			spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
			spin_unlock_irqrestore(&port->port_lock, flags);
			return -ENOMEM;
		}

		d->tx_req->context = port;
		d->tx_req->complete = gbam_endless_tx_complete;
		d->tx_req->length = 0;
		d->tx_req->no_interrupt = 1;
	}

	if (d->trans == USB_GADGET_XPORT_BAM) {
		d->to_host = 0;
		d->to_modem = 0;