From e2e55cdec555ffc492ca5b5e91569da1ae8e11b2 Mon Sep 17 00:00:00 2001 From: Subrat Dash Date: Thu, 3 Oct 2019 15:30:48 +0530 Subject: [PATCH] qcacmn: Fix Invalid HTC endpoint is observed in the rx header The urb completion handler is asynchronous. Sometimes it is called before prestart allocation is complete. The urb_prestart_cnt is accessed unsynchronized manner from usb_hif_usb_recv_prestart_complete. It presumes that it is running out of prestart URBs and new allocation will be done. Since bundling is not enabled at this point, the new URBs allocated are not considered for bundling. Use spin_lock to ensure synchronization in the above scenario. Change-Id: I8c989aff7985a9ab614d63a71c7f97a0278647e0 CRs-Fixed: 2538796 --- hif/src/usb/hif_usb.c | 1 + hif/src/usb/if_usb.h | 3 ++- hif/src/usb/usbdrv.c | 10 +++++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/hif/src/usb/hif_usb.c b/hif/src/usb/hif_usb.c index b37df5b030c9..8ed33841763e 100644 --- a/hif/src/usb/hif_usb.c +++ b/hif/src/usb/hif_usb.c @@ -384,6 +384,7 @@ QDF_STATUS hif_usb_device_init(struct hif_usb_softc *sc) qdf_spinlock_create(&(device->cs_lock)); qdf_spinlock_create(&(device->rx_lock)); qdf_spinlock_create(&(device->tx_lock)); + qdf_spinlock_create(&device->rx_prestart_lock); device->udev = dev; device->interface = interface; diff --git a/hif/src/usb/if_usb.h b/hif/src/usb/if_usb.h index 35d83af601d7..1dd384055944 100644 --- a/hif/src/usb/if_usb.h +++ b/hif/src/usb/if_usb.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -117,6 +117,7 @@ struct HIF_DEVICE_USB { qdf_spinlock_t cs_lock; qdf_spinlock_t tx_lock; qdf_spinlock_t rx_lock; + qdf_spinlock_t rx_prestart_lock; struct hif_msg_callbacks htc_callbacks; struct usb_device *udev; struct usb_interface *interface; diff --git a/hif/src/usb/usbdrv.c b/hif/src/usb/usbdrv.c index 7e62ff6015ab..1950b1f9503a 100644 --- a/hif/src/usb/usbdrv.c +++ b/hif/src/usb/usbdrv.c @@ -602,8 +602,10 @@ static void usb_hif_usb_recv_prestart_complete usb_hif_cleanup_recv_urb(urb_context); /* Prestart URBs runs out and now start working receive pipe. */ + qdf_spin_lock_irqsave(&pipe->device->rx_prestart_lock); if ((--pipe->urb_prestart_cnt == 0) && !sc->suspend_state) usb_hif_start_recv_pipes(pipe->device); + qdf_spin_unlock_irqrestore(&pipe->device->rx_prestart_lock); HIF_DBG("-%s", __func__); } @@ -855,6 +857,7 @@ static void usb_hif_post_recv_prestart_transfers(struct HIF_USB_PIPE *recv_pipe, HIF_TRACE("+%s", __func__); + qdf_spin_lock_irqsave(&recv_pipe->device->rx_prestart_lock); for (i = 0; i < prestart_urb; i++) { urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe); if (!urb_context) @@ -886,7 +889,6 @@ static void usb_hif_post_recv_prestart_transfers(struct HIF_USB_PIPE *recv_pipe, urb_context->buf); usb_hif_enqueue_pending_transfer(recv_pipe, urb_context); - usb_status = usb_submit_urb(urb, GFP_ATOMIC); if (usb_status) { @@ -898,6 +900,7 @@ static void usb_hif_post_recv_prestart_transfers(struct HIF_USB_PIPE *recv_pipe, } recv_pipe->urb_prestart_cnt++; } + qdf_spin_unlock_irqrestore(&recv_pipe->device->rx_prestart_lock); HIF_TRACE("-%s", __func__); } @@ -1071,8 +1074,9 @@ void usb_hif_start_recv_pipes(struct HIF_DEVICE_USB *device) pipe = &device->pipes[HIF_RX_DATA_PIPE]; pipe->urb_cnt_thresh = pipe->urb_alloc / 2; - HIF_TRACE("Post URBs to RX_DATA_PIPE: %d", - device->pipes[HIF_RX_DATA_PIPE].urb_cnt); + HIF_TRACE("Post URBs to RX_DATA_PIPE: %d is_bundle %d", + device->pipes[HIF_RX_DATA_PIPE].urb_cnt, + device->is_bundle_enabled); if (device->is_bundle_enabled) { usb_hif_post_recv_bundle_transfers(pipe, pipe->device->rx_bundle_buf_len);