Merge changes  into wlan-cmn.driver.lnx.2.0
diff --git a/hif/inc/hif.h b/hif/inc/hif.h
index de46bd4..7d190a1 100644
--- a/hif/inc/hif.h
+++ b/hif/inc/hif.h
@@ -465,8 +465,8 @@
  * enum hif_device_config_opcode: configure mode
  *
  * @HIF_DEVICE_POWER_STATE: device power state
- * @HIF_DEVICE_GET_MBOX_BLOCK_SIZE: get mbox block size
- * @HIF_DEVICE_GET_MBOX_ADDR: get mbox block address
+ * @HIF_DEVICE_GET_BLOCK_SIZE: get block size
+ * @HIF_DEVICE_GET_ADDR: get block address
  * @HIF_DEVICE_GET_PENDING_EVENTS_FUNC: get pending events functions
  * @HIF_DEVICE_GET_IRQ_PROC_MODE: get irq proc mode
  * @HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC: receive event function
diff --git a/hif/src/dispatcher/multibus_sdio.c b/hif/src/dispatcher/multibus_sdio.c
index 3c220be..c5962a9 100644
--- a/hif/src/dispatcher/multibus_sdio.c
+++ b/hif/src/dispatcher/multibus_sdio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-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
@@ -25,8 +25,8 @@
 #include "if_sdio.h"
 
 /**
- * hif_initialize_sdio_ops() - initialize the pci ops
- * @bus_ops: hif_bus_ops table pointer to initialize
+ * hif_initialize_sdio_ops() - initialize the sdio ops
+ * @hif_sc: hif soft context
  *
  * Return: QDF_STATUS_SUCCESS
  */
diff --git a/hif/src/sdio/hif_diag_reg_access.c b/hif/src/sdio/hif_diag_reg_access.c
index 0f4d50c..30e3635 100644
--- a/hif/src/sdio/hif_diag_reg_access.c
+++ b/hif/src/sdio/hif_diag_reg_access.c
@@ -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
@@ -26,7 +26,7 @@
 #include "hif.h"
 #include "if_sdio.h"
 #include "regtable_sdio.h"
-
+#include "hif_sdio_dev.h"
 #include "qdf_module.h"
 
 #define CPU_DBG_SEL_ADDRESS                      0x00000483
diff --git a/hif/src/sdio/hif_sdio_common.h b/hif/src/sdio/hif_sdio_common.h
index dc0900d..21977f2 100644
--- a/hif/src/sdio/hif_sdio_common.h
+++ b/hif/src/sdio/hif_sdio_common.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
@@ -26,11 +26,13 @@
 #define MANUFACTURER_ID_AR6320_BASE        0x500
 #define MANUFACTURER_ID_QCA9377_BASE       0x700
 #define MANUFACTURER_ID_QCA9379_BASE       0x800
-#define MANUFACTURER_ID_QCN7605_BASE       0x0000 /*TODO - GenoaSDIO */
+#define MANUFACTURER_ID_QCN7605            0x400B
+#define MANUFACTURER_ID_QCN7605_BASE       0x4000
 #define MANUFACTURER_ID_AR6K_BASE_MASK     0xFF00
 #define MANUFACTURER_ID_AR6K_REV_MASK      0x00FF
 #define FUNCTION_CLASS                     0x0
-#define MANUFACTURER_CODE                  0x271
+#define MANUFACTURER_CODE                  0x271 /* Atheros Manufacturer ID */
+#define MANUFACTURER_QC_CODE               0x70  /* QC Manufacturer ID */
 
 
 #endif /* _HIF_SDIO_COMMON_H_ */
diff --git a/hif/src/sdio/hif_sdio_dev.c b/hif/src/sdio/hif_sdio_dev.c
index 253cf27..ba2277a 100644
--- a/hif/src/sdio/hif_sdio_dev.c
+++ b/hif/src/sdio/hif_sdio_dev.c
@@ -208,127 +208,6 @@
 	return status;
 }
 
-#define DEV_CHECK_RECV_YIELD(pdev) \
-	((pdev)->CurrentDSRRecvCount >= \
-	 (pdev)->HifIRQYieldParams.recv_packet_yield_count)
-
-/**
- * hif_dev_dsr_handler() - Synchronous interrupt handler
- *
- * @context: hif send context
- *
- * Return: 0 for success and non-zero for failure
- */
-QDF_STATUS hif_dev_dsr_handler(void *context)
-{
-	struct hif_sdio_device *pdev = (struct hif_sdio_device *)context;
-	QDF_STATUS status = QDF_STATUS_SUCCESS;
-	bool done = false;
-	bool async_proc = false;
-
-	HIF_ENTER();
-
-	/* reset the recv counter that tracks when we need
-	 * to yield from the DSR
-	 */
-	pdev->CurrentDSRRecvCount = 0;
-	/* reset counter used to flag a re-scan of IRQ
-	 * status registers on the target
-	 */
-	pdev->RecheckIRQStatusCnt = 0;
-
-	while (!done) {
-		status = hif_dev_process_pending_irqs(pdev, &done, &async_proc);
-		if (QDF_IS_STATUS_ERROR(status))
-			break;
-
-		if (pdev->HifIRQProcessingMode == HIF_DEVICE_IRQ_SYNC_ONLY) {
-			/* the HIF layer does not allow async IRQ processing,
-			 * override the asyncProc flag
-			 */
-			async_proc = false;
-			/* this will cause us to re-enter ProcessPendingIRQ()
-			 * and re-read interrupt status registers.
-			 * This has a nice side effect of blocking us until all
-			 * async read requests are completed. This behavior is
-			 * required as we  do not allow ASYNC processing
-			 * in interrupt handlers (like Windows CE)
-			 */
-
-			if (pdev->DSRCanYield && DEV_CHECK_RECV_YIELD(pdev))
-				/* ProcessPendingIRQs() pulled enough recv
-				 * messages to satisfy the yield count, stop
-				 * checking for more messages and return
-				 */
-				break;
-		}
-
-		if (async_proc) {
-			/* the function does some async I/O for performance,
-			 * we need to exit the ISR immediately, the check below
-			 * will prevent the interrupt from being
-			 * Ack'd while we handle it asynchronously
-			 */
-			break;
-		}
-	}
-
-	if (QDF_IS_STATUS_SUCCESS(status) && !async_proc) {
-		/* Ack the interrupt only if :
-		 *  1. we did not get any errors in processing interrupts
-		 *  2. there are no outstanding async processing requests
-		 */
-		if (pdev->DSRCanYield) {
-			/* if the DSR can yield do not ACK the interrupt, there
-			 * could be more pending messages. The HIF layer
-			 * must ACK the interrupt on behalf of HTC
-			 */
-			HIF_INFO("%s:  Yield (RX count: %d)",
-				 __func__, pdev->CurrentDSRRecvCount);
-		} else {
-			HIF_INFO("%s: Ack interrupt", __func__);
-			hif_ack_interrupt(pdev->HIFDevice);
-		}
-	}
-
-	HIF_EXIT();
-	return status;
-}
-
-/** hif_dev_set_mailbox_swap() - Set the mailbox swap from firmware
- * @pdev : The HIF layer object
- *
- * Return: none
- */
-void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev)
-{
-	struct hif_sdio_device *hif_device = hif_dev_from_hif(pdev);
-
-	HIF_ENTER();
-
-	hif_device->swap_mailbox = true;
-
-	HIF_EXIT();
-}
-
-/** hif_dev_get_mailbox_swap() - Get the mailbox swap setting
- * @pdev : The HIF layer object
- *
- * Return: none
- */
-bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev)
-{
-	struct hif_sdio_device *hif_device;
-
-	HIF_ENTER();
-
-	hif_device = hif_dev_from_hif(pdev);
-
-	HIF_EXIT();
-
-	return hif_device->swap_mailbox;
-}
-
 /**
  * hif_dev_setup() - set up sdio device.
  * @pDev: sdio device context
@@ -346,7 +225,6 @@
 
 	status = hif_dev_setup_device(pdev);
 
-
 	if (status != QDF_STATUS_SUCCESS) {
 		HIF_ERROR("%s: device specific setup failed", __func__);
 		return QDF_STATUS_E_INVAL;
diff --git a/hif/src/sdio/hif_sdio_dev.h b/hif/src/sdio/hif_sdio_dev.h
index 5dbe682..7ee6582 100644
--- a/hif/src/sdio/hif_sdio_dev.h
+++ b/hif/src/sdio/hif_sdio_dev.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, 2018-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
@@ -26,6 +26,7 @@
 #include <hif.h>
 #include "athstartpack.h"
 #include "hif_internal.h"
+#include "if_sdio.h"
 
 struct hif_sdio_device *hif_dev_from_hif(struct hif_sdio_dev *hif_device);
 
@@ -47,7 +48,7 @@
 
 QDF_STATUS hif_dev_process_pending_irqs(struct hif_sdio_device *pdev,
 					bool *done,
-					      bool *async_processing);
+					bool *async_processing);
 
 void hif_dev_mask_interrupts(struct hif_sdio_device *pdev);
 
@@ -60,9 +61,9 @@
 
 int hif_dev_setup_device(struct hif_sdio_device *pdev);
 
-QDF_STATUS hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
-				    struct hif_device_mbox_info *config,
-				    uint32_t config_len);
+int hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
+			     void *config,
+			     uint32_t config_len);
 
 void hif_dev_get_block_size(void *config);
 
@@ -70,8 +71,93 @@
 
 bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev);
 
-int hif_sdio_set_drvdata(struct sdio_func *func,
-			 struct hif_sdio_dev *hifdevice);
+QDF_STATUS hif_read_write(struct hif_sdio_dev *device, unsigned long address,
+			  char *buffer,	uint32_t length, uint32_t request,
+			  void *context);
 
-struct hif_sdio_dev *get_hif_device(struct sdio_func *func);
+#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
+static inline struct hif_sdio_dev *get_hif_device(struct hif_softc *hif_ctx,
+						  struct sdio_func *func)
+{
+	qdf_assert(func);
+	return (struct hif_sdio_dev *)sdio_get_drvdata(func);
+}
+
+/**
+ * hif_sdio_set_drvdata() - set wlan driver data into upper layer private
+ * @hif_ctx: HIF object
+ * @func: pointer to sdio function
+ * @hifdevice: pointer to hif device
+ *
+ * Return: zero for success.
+ */
+static inline int hif_sdio_set_drvdata(struct hif_softc *hif_ctx,
+				       struct sdio_func *func,
+				       struct hif_sdio_dev *hifdevice)
+{
+	sdio_set_drvdata(func, hifdevice);
+	return 0;
+}
+
+static inline int hif_dev_configure_pipes(struct hif_sdio_dev *pdev,
+					  struct sdio_func *func)
+{
+	return 0;
+}
+
+static inline int hif_dev_register_channels(struct hif_sdio_dev *dev,
+					    struct sdio_func *func)
+{
+	return 0;
+}
+
+static inline void hif_dev_unregister_channels(struct hif_sdio_dev *dev,
+					       struct sdio_func *func)
+{
+}
+#else
+static inline struct hif_sdio_dev *get_hif_device(struct hif_softc *hif_ctx,
+						  struct sdio_func *func)
+{
+	struct hif_sdio_softc *scn = (struct hif_sdio_softc *)hif_ctx;
+
+	return (struct hif_sdio_dev *)scn->hif_handle;
+}
+
+/**
+ * hif_sdio_set_drvdata() - set wlan driver data into upper layer private
+ * @hif_ctx: HIF object
+ * @func: pointer to sdio function
+ * @hifdevice: pointer to hif device
+ *
+ * Return: zero for success.
+ */
+static inline int hif_sdio_set_drvdata(struct hif_softc *hif_ctx,
+				       struct sdio_func *func,
+				       struct hif_sdio_dev *hifdevice)
+{
+	struct hif_sdio_softc *sc = (struct hif_sdio_softc *)hif_ctx;
+
+	sc->hif_handle = hifdevice;
+
+	return 0;
+}
+
+int hif_dev_configure_pipes(struct hif_sdio_dev *pdev,
+			    struct sdio_func *func);
+
+int hif_dev_register_channels(struct hif_sdio_dev *dev,
+			      struct sdio_func *func);
+
+void hif_dev_unregister_channels(struct hif_sdio_dev *dev,
+				 struct sdio_func *func);
+#endif /* SDIO_TRANSFER */
+QDF_STATUS hif_enable_func(struct hif_softc *ol_sc, struct hif_sdio_dev *device,
+			   struct sdio_func *func, bool resume);
+QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
+			    struct sdio_func *func,
+			    bool reset);
+A_STATUS hif_sdio_probe(struct hif_softc *ol_sc,
+			struct sdio_func *func,
+			struct hif_sdio_dev *device);
 #endif /* HIF_SDIO_DEV_H_ */
diff --git a/hif/src/sdio/hif_sdio_internal.h b/hif/src/sdio/hif_sdio_internal.h
index 67c8ebf..b378575 100644
--- a/hif/src/sdio/hif_sdio_internal.h
+++ b/hif/src/sdio/hif_sdio_internal.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016-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
@@ -28,7 +28,7 @@
 #if defined(CONFIG_SDIO_TRANSFER_MAILBOX)
 #include <transfer/mailbox.h>
 #elif defined(CONFIG_SDIO_TRANSFER_ADMA)
-#error "Error - Not implemented yet"
+#include <transfer/adma.h>
 #else
 #error "Error - Invalid transfer method"
 #endif
@@ -54,7 +54,6 @@
 	qdf_spinlock_t TxLock;
 	qdf_spinlock_t RxLock;
 	struct hif_msg_callbacks hif_callbacks;
-	struct hif_device_mbox_info MailBoxInfo;
 	uint32_t BlockSize;
 	uint32_t BlockMask;
 	enum hif_device_irq_mode HifIRQProcessingMode;
@@ -65,8 +64,11 @@
 	int RecheckIRQStatusCnt;
 	uint32_t RecvStateFlags;
 	void *pTarget;
-	bool swap_mailbox;
 	struct devRegisters devRegisters;
+#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
+	bool swap_mailbox;
+	struct hif_device_mbox_info MailBoxInfo;
+#endif
 };
 
 #define LOCK_HIF_DEV(device)    qdf_spin_lock(&(device)->Lock)
diff --git a/hif/src/sdio/if_sdio.c b/hif/src/sdio/if_sdio.c
index 0b98d0b..102b84d 100644
--- a/hif/src/sdio/if_sdio.c
+++ b/hif/src/sdio/if_sdio.c
@@ -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
@@ -181,7 +181,7 @@
 {
 	struct sdio_func *func = dev_to_sdio_func(hif_sc->qdf_dev->dev);
 
-	hif_sdio_device_removed(func);
+	hif_sdio_device_removed(hif_sc, func);
 }
 
 /**
diff --git a/hif/src/sdio/if_sdio.h b/hif/src/sdio/if_sdio.h
index 1891c8b..191ea61 100644
--- a/hif/src/sdio/if_sdio.h
+++ b/hif/src/sdio/if_sdio.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
@@ -83,7 +83,7 @@
 			     const struct sdio_device_id *id);
 void hif_sdio_stop(struct hif_softc *hif_ctx);
 void hif_sdio_shutdown(struct hif_softc *hif_ctx);
-void hif_sdio_device_removed(struct sdio_func *func);
+void hif_sdio_device_removed(struct hif_softc *hif_ctx, struct sdio_func *func);
 int hif_device_suspend(struct hif_softc *ol_sc, struct device *dev);
 int hif_device_resume(struct hif_softc *ol_sc, struct device *dev);
 void hif_register_tbl_attach(struct hif_softc *scn,
diff --git a/hif/src/sdio/native_sdio/include/hif_internal.h b/hif/src/sdio/native_sdio/include/hif_internal.h
index 8f2719a..41001c8 100644
--- a/hif/src/sdio/native_sdio/include/hif_internal.h
+++ b/hif/src/sdio/native_sdio/include/hif_internal.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
@@ -35,6 +35,7 @@
 #include <qdf_status.h>
 #include <qdf_timer.h>
 #include <qdf_atomic.h>
+#include <qdf_list.h>
 #include "hif.h"
 #include "hif_debug.h"
 #include "hif_sdio_common.h"
@@ -167,7 +168,7 @@
 	struct bus_request *next;       /* link list of available requests */
 	struct bus_request *inusenext;  /* link list of in use requests */
 	struct semaphore sem_req;
-	uint32_t address;       /* request data */
+	unsigned long address;       /* request data */
 	char *buffer;
 	uint32_t length;
 	uint32_t request;
@@ -176,6 +177,14 @@
 	struct HIF_SCATTER_REQ_PRIV *scatter_req;
 };
 
+#define HIF_ADMA_MAX_CHANS 2
+#ifdef CONFIG_SDIO_TRANSFER_ADMA
+struct rx_q_entry {
+	qdf_list_node_t entry;
+	qdf_nbuf_t nbuf;
+};
+#endif
+
 struct hif_sdio_dev {
 	struct sdio_func *func;
 	qdf_spinlock_t asynclock;
@@ -201,6 +210,15 @@
 	const struct sdio_device_id *id;
 	struct mmc_host *host;
 	void *htc_context;
+#ifdef CONFIG_SDIO_TRANSFER_ADMA
+	struct sdio_al_client_handle *al_client;
+	struct sdio_al_channel_handle *al_chan[HIF_ADMA_MAX_CHANS];
+	uint8_t adma_chans_used;
+	qdf_list_t rx_q;
+	qdf_spinlock_t rx_q_lock;
+	qdf_work_t rx_q_alloc_work;
+	bool rx_q_alloc_work_scheduled;
+#endif
 };
 
 struct HIF_DEVICE_OS_DEVICE_INFO {
@@ -270,18 +288,13 @@
 QDF_STATUS hif_attach_htc(struct hif_sdio_dev *device,
 			  struct htc_callbacks *callbacks);
 
-QDF_STATUS hif_read_write(struct hif_sdio_dev *device,
-			uint32_t address,
-			char *buffer,
-			uint32_t length, uint32_t request, void *context);
-
 void hif_ack_interrupt(struct hif_sdio_dev *device);
 
 void hif_mask_interrupt(struct hif_sdio_dev *device);
 
 void hif_un_mask_interrupt(struct hif_sdio_dev *device);
 
-void hif_sdio_configure_pipes(struct hif_sdio_dev *dev, struct sdio_func *func);
+int hif_sdio_configure_pipes(struct hif_sdio_dev *dev, struct sdio_func *func);
 
 struct _HIF_SCATTER_ITEM {
 	u_int8_t     *buffer; /* CPU accessible address of buffer */
@@ -400,14 +413,14 @@
 #define SDIO_SET_CMD52_WRITE_ARG(arg, func, address, value) \
 	SDIO_SET_CMD52_ARG(arg, 1, (func), 0, address, value)
 
-void hif_sdio_quirk_force_drive_strength(struct sdio_func *func);
-void hif_sdio_quirk_write_cccr(struct sdio_func *func);
-int hif_sdio_quirk_mod_strength(struct sdio_func *func);
-int hif_sdio_quirk_async_intr(struct sdio_func *func);
-int hif_sdio_set_bus_speed(struct sdio_func *func);
-int hif_sdio_set_bus_width(struct sdio_func *func);
-int hif_sdio_func_enable(struct hif_sdio_dev *device,
-			 struct sdio_func *func);
+void hif_sdio_quirk_force_drive_strength(struct hif_softc *ol_sc,
+					 struct sdio_func *func);
+void hif_sdio_quirk_write_cccr(struct hif_softc *ol_sc, struct sdio_func *func);
+int hif_sdio_quirk_mod_strength(struct hif_softc *ol_sc,
+				struct sdio_func *func);
+int hif_sdio_quirk_async_intr(struct hif_softc *ol_sc, struct sdio_func *func);
+int hif_sdio_set_bus_speed(struct hif_softc *ol_sc, struct sdio_func *func);
+int hif_sdio_set_bus_width(struct hif_softc *ol_sc, struct sdio_func *func);
 QDF_STATUS hif_sdio_func_disable(struct hif_sdio_dev *device,
 				 struct sdio_func *func,
 				 bool reset);
diff --git a/hif/src/sdio/native_sdio/src/dev_quirks.c b/hif/src/sdio/native_sdio/src/dev_quirks.c
index b84f1ab..7c7e63b 100644
--- a/hif/src/sdio/native_sdio/src/dev_quirks.c
+++ b/hif/src/sdio/native_sdio/src/dev_quirks.c
@@ -1,8 +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
@@ -91,8 +88,10 @@
 MODULE_PARM_DESC(brokenirq,
 		 "Set as 1 to use polling method instead of interrupt mode");
 
+#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
 /**
  * hif_sdio_force_drive_strength() - Set SDIO drive strength
+ * @ol_sc: softc instance
  * @func: pointer to sdio_func
  *
  * This function forces the driver strength of the SDIO
@@ -100,61 +99,156 @@
  *
  * Return: none.
  */
-void hif_sdio_quirk_force_drive_strength(struct sdio_func *func)
+void hif_sdio_quirk_force_drive_strength(struct hif_softc *ol_sc,
+					 struct sdio_func *func)
 {
 	int err = 0;
 	unsigned char value = 0;
 	uint32_t mask = 0, addr = SDIO_CCCR_DRIVE_STRENGTH;
-	struct hif_sdio_dev *device = sdio_get_drvdata(func);
 
-	uint16_t  manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
-
-	switch (manfid) {
-	case MANUFACTURER_ID_QCN7605_BASE:
-		break;
-	default:
-		err = func0_cmd52_read_byte(func->card, addr, &value);
-		if (err) {
-			HIF_ERROR("%s: read driver strength 0x%02X fail %d\n",
-				  __func__, addr, err);
-			break;
-		}
-
-		mask = (SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT);
-		value = (value & ~mask) | SDIO_DTSx_SET_TYPE_D;
-		err = func0_cmd52_write_byte(func->card, addr, value);
-		if (err) {
-			HIF_ERROR("%s: write driver strength failed", __func__);
-			HIF_ERROR("%s: 0x%02X to 0x%02X failed: %d\n", __func__,
-				  (uint32_t)value, addr, err);
-			break;
-		}
-
-		value = 0;
-		addr = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR;
-		err = func0_cmd52_read_byte(func->card,	addr, &value);
-		if (err) {
-			HIF_ERROR("%s Read CCCR 0x%02X failed: %d\n",
-				  __func__, addr, err);
-			break;
-		}
-
-		mask = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK;
-		value = (value & ~mask) |
-			CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A |
-			CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C |
-			CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D;
-		err = func0_cmd52_write_byte(func->card, addr, value);
-		if (err)
-			HIF_ERROR("%s Write CCCR 0x%02X to 0x%02X failed: %d\n",
-				  __func__, addr, value, err);
-
-		break;
+	err = func0_cmd52_read_byte(func->card, addr, &value);
+	if (err) {
+		HIF_ERROR("%s: read driver strength 0x%02X fail %d\n",
+			  __func__, addr, err);
+		return;
 	}
+
+	mask = (SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT);
+	value = (value & ~mask) | SDIO_DTSx_SET_TYPE_D;
+	err = func0_cmd52_write_byte(func->card, addr, value);
+	if (err) {
+		HIF_ERROR("%s: write driver strength failed", __func__);
+		HIF_ERROR("%s: 0x%02X to 0x%02X failed: %d\n", __func__,
+			  (uint32_t)value, addr, err);
+		return;
+	}
+
+	value = 0;
+	addr = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR;
+	err = func0_cmd52_read_byte(func->card,	addr, &value);
+	if (err) {
+		HIF_ERROR("%s Read CCCR 0x%02X failed: %d\n",
+			  __func__, addr, err);
+		return;
+	}
+
+	mask = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK;
+	value = (value & ~mask) | CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A |
+		CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C |
+		CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D;
+	err = func0_cmd52_write_byte(func->card, addr, value);
+	if (err)
+		HIF_ERROR("%s Write CCCR 0x%02X to 0x%02X failed: %d\n",
+			  __func__, addr, value, err);
 }
 
 /**
+ * hif_sdio_quirk_async_intr() - Set asynchronous interrupt settings
+ * @ol_sc: softc instance
+ * @func: pointer to sdio_func
+ *
+ * The values are taken from the module parameter asyncintdelay
+ * Call this with the sdhci host claimed
+ *
+ * Return: none.
+ */
+int hif_sdio_quirk_async_intr(struct hif_softc *ol_sc, struct sdio_func *func)
+{
+	uint8_t data;
+	uint16_t manfid;
+	int set_async_irq = 0, ret = 0;
+	struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
+
+	manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
+
+	switch (manfid) {
+	case MANUFACTURER_ID_AR6003_BASE:
+		set_async_irq = 1;
+		ret =
+		func0_cmd52_write_byte(func->card,
+				       CCCR_SDIO_IRQ_MODE_REG_AR6003,
+				       SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6003);
+		if (ret)
+			return ret;
+		break;
+	case MANUFACTURER_ID_AR6320_BASE:
+	case MANUFACTURER_ID_QCA9377_BASE:
+	case MANUFACTURER_ID_QCA9379_BASE:
+		set_async_irq = 1;
+		ret = func0_cmd52_read_byte(func->card,
+					    CCCR_SDIO_IRQ_MODE_REG_AR6320,
+					    &data);
+		if (ret)
+			return ret;
+
+		data |= SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6320;
+		ret = func0_cmd52_write_byte(func->card,
+					     CCCR_SDIO_IRQ_MODE_REG_AR6320,
+					     data);
+		if (ret)
+			return ret;
+		break;
+	}
+
+	if (asyncintdelay) {
+		/* Set CCCR 0xF0[7:6] to increase async interrupt delay clock
+		 * to fix interrupt missing issue on dell 8460p
+		 */
+
+		ret = func0_cmd52_read_byte(func->card,
+					    CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
+					    &data);
+		if (ret)
+			return ret;
+
+		data = (data & ~CCCR_SDIO_ASYNC_INT_DELAY_MASK) |
+			((asyncintdelay << CCCR_SDIO_ASYNC_INT_DELAY_LSB) &
+			 CCCR_SDIO_ASYNC_INT_DELAY_MASK);
+
+		ret = func0_cmd52_write_byte(func->card,
+					     CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
+					     data);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+#else
+/**
+ * hif_sdio_force_drive_strength() - Set SDIO drive strength
+ * @ol_sc: softc instance
+ * @func: pointer to sdio_func
+ *
+ * This function forces the driver strength of the SDIO
+ * Call this with the sdhci host claimed
+ *
+ * Return: none.
+ */
+void hif_sdio_quirk_force_drive_strength(struct hif_softc *ol_sc,
+					 struct sdio_func *func)
+{
+}
+
+/**
+ * hif_sdio_quirk_async_intr() - Set asynchronous interrupt settings
+ * @ol_sc: softc instance
+ * @func: pointer to sdio_func
+ *
+ * The values are taken from the module parameter asyncintdelay
+ * Call this with the sdhci host claimed
+ *
+ * Return: none.
+ */
+int hif_sdio_quirk_async_intr(struct hif_softc *ol_sc, struct sdio_func *func)
+{
+	return 0;
+}
+#endif
+
+/**
  * hif_sdio_quirk_write_cccr() - write a desired CCCR register
+ * @ol_sc: softc instance
  * @func: pointer to sdio_func
  *
  * The values are taken from the module parameter writecccr
@@ -162,7 +256,7 @@
  *
  * Return: none.
  */
-void hif_sdio_quirk_write_cccr(struct sdio_func *func)
+void hif_sdio_quirk_write_cccr(struct hif_softc *ol_sc, struct sdio_func *func)
 {
 	int32_t err;
 
@@ -231,6 +325,7 @@
 
 /**
  * hif_sdio_quirk_mod_strength() - write a desired CCCR register
+ * @ol_sc: softc instance
  * @func: pointer to sdio_func
  *
  * The values are taken from the module parameter writecccr
@@ -238,11 +333,11 @@
  *
  * Return: none.
  */
-int hif_sdio_quirk_mod_strength(struct sdio_func *func)
+int hif_sdio_quirk_mod_strength(struct hif_softc *ol_sc, struct sdio_func *func)
 {
 	int ret = 0;
 	uint32_t addr, value;
-	struct hif_sdio_dev *device = sdio_get_drvdata(func);
+	struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
 	uint16_t  manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
 
 	if (!modstrength) /* TODO: Dont set this : scn is not popolated yet */
@@ -287,82 +382,6 @@
 	return ret;
 }
 
-/**
- * hif_sdio_quirk_async_intr() - Set asynchronous interrupt settings
- * @func: pointer to sdio_func
- *
- * The values are taken from the module parameter asyncintdelay
- * Call this with the sdhci host claimed
- *
- * Return: none.
- */
-int hif_sdio_quirk_async_intr(struct sdio_func *func)
-{
-	uint8_t data;
-	uint16_t manfid;
-	int set_async_irq = 0, ret = 0;
-	struct hif_sdio_dev *device = sdio_get_drvdata(func);
-
-	manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
-
-	switch (manfid) {
-	case MANUFACTURER_ID_AR6003_BASE:
-		set_async_irq = 1;
-		ret =
-		func0_cmd52_write_byte(func->card,
-				       CCCR_SDIO_IRQ_MODE_REG_AR6003,
-				       SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6003);
-		if (ret)
-			return ret;
-		break;
-	case MANUFACTURER_ID_AR6320_BASE:
-	case MANUFACTURER_ID_QCA9377_BASE:
-	case MANUFACTURER_ID_QCA9379_BASE:
-		set_async_irq = 1;
-		ret = func0_cmd52_read_byte(func->card,
-					    CCCR_SDIO_IRQ_MODE_REG_AR6320,
-					    &data);
-		if (ret)
-			return ret;
-
-		data |= SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6320;
-		ret = func0_cmd52_write_byte(func->card,
-					     CCCR_SDIO_IRQ_MODE_REG_AR6320,
-					     data);
-		if (ret)
-			return ret;
-		break;
-	case MANUFACTURER_ID_QCN7605_BASE:
-		/* No async intr delay settings */
-		asyncintdelay = 0;
-		return ret;
-	}
-
-	if (asyncintdelay) {
-		/* Set CCCR 0xF0[7:6] to increase async interrupt delay clock
-		 * to fix interrupt missing issue on dell 8460p
-		 */
-
-		ret = func0_cmd52_read_byte(func->card,
-					    CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
-					    &data);
-		if (ret)
-			return ret;
-
-		data = (data & ~CCCR_SDIO_ASYNC_INT_DELAY_MASK) |
-			((asyncintdelay << CCCR_SDIO_ASYNC_INT_DELAY_LSB) &
-			 CCCR_SDIO_ASYNC_INT_DELAY_MASK);
-
-		ret = func0_cmd52_write_byte(func->card,
-					     CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS,
-					     data);
-		if (ret)
-			return ret;
-	}
-
-	return ret;
-}
-
 #if KERNEL_VERSION(3, 4, 0) <= LINUX_VERSION_CODE
 #ifdef SDIO_BUS_WIDTH_8BIT
 static int hif_cmd52_write_byte_8bit(struct sdio_func *func)
@@ -381,14 +400,15 @@
 
 /**
  * hif_sdio_set_bus_speed() - Set the sdio bus speed
+ * @ol_sc: softc instance
  * @func: pointer to sdio_func
  *
  * Return: 0 on success, error number otherwise.
  */
-int hif_sdio_set_bus_speed(struct sdio_func *func)
+int hif_sdio_set_bus_speed(struct hif_softc *ol_sc, struct sdio_func *func)
 {
 	uint32_t clock, clock_set = 12500000;
-	struct hif_sdio_dev *device = get_hif_device(func);
+	struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
 	uint16_t manfid;
 
 	manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
@@ -427,16 +447,17 @@
 
 /**
  * hif_set_bus_width() - Set the sdio bus width
+ * @ol_sc: softc instance
  * @func: pointer to sdio_func
  *
  * Return: 0 on success, error number otherwise.
  */
-int hif_sdio_set_bus_width(struct sdio_func *func)
+int hif_sdio_set_bus_width(struct hif_softc *ol_sc, struct sdio_func *func)
 {
 	int ret = 0;
 	uint16_t manfid;
 	uint8_t data = 0;
-	struct hif_sdio_dev *device = get_hif_device(func);
+	struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
 
 	manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
 
@@ -491,66 +512,6 @@
 	return ret;
 }
 
-/**
- * hif_sdio_func_enable() - Handle device enabling as per device
- * @device: HIF device object
- * @func: function pointer
- *
- * Return success or failure
- */
-int hif_sdio_func_enable(struct hif_sdio_dev *device,
-			 struct sdio_func *func)
-{
-	uint16_t manfid;
-
-	manfid = device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK;
-
-	if (manfid == MANUFACTURER_ID_QCN7605_BASE)
-		return 0;
-
-	if (device->is_disabled) {
-		int ret = 0;
-
-		sdio_claim_host(func);
-
-		ret = hif_sdio_quirk_async_intr(func);
-		if (ret) {
-			HIF_ERROR("%s: Error setting async intr:%d",
-				  __func__, ret);
-			sdio_release_host(func);
-			return QDF_STATUS_E_FAILURE;
-		}
-
-		func->enable_timeout = 100;
-		ret = sdio_enable_func(func);
-		if (ret) {
-			HIF_ERROR("%s: Unable to enable function: %d",
-				  __func__, ret);
-			sdio_release_host(func);
-			return QDF_STATUS_E_FAILURE;
-		}
-
-		ret = sdio_set_block_size(func, HIF_BLOCK_SIZE);
-		if (ret) {
-			HIF_ERROR("%s: Unable to set block size 0x%X : %d\n",
-				  __func__, HIF_BLOCK_SIZE, ret);
-			sdio_release_host(func);
-			return QDF_STATUS_E_FAILURE;
-		}
-
-		ret = hif_sdio_quirk_mod_strength(func);
-		if (ret) {
-			HIF_ERROR("%s: Error setting mod strength : %d\n",
-				  __func__, ret);
-			sdio_release_host(func);
-			return QDF_STATUS_E_FAILURE;
-		}
-
-		sdio_release_host(func);
-	}
-
-	return 0;
-}
 
 /**
  * hif_mask_interrupt() - Disable hif device irq
@@ -594,11 +555,7 @@
  */
 static void hif_irq_handler(struct sdio_func *func)
 {
-	struct hif_sdio_dev *device;
-
-	HIF_ENTER();
-
-	device = get_hif_device(func);
+	struct hif_sdio_dev *device = get_hif_device(NULL, func);
 	atomic_set(&device->irq_handling, 1);
 	/* release the host during intr so we can use
 	 * it when we process cmds
@@ -607,8 +564,6 @@
 	device->htc_callbacks.dsr_handler(device->htc_callbacks.context);
 	sdio_claim_host(device->func);
 	atomic_set(&device->irq_handling, 0);
-
-	HIF_EXIT();
 }
 
 /**
diff --git a/hif/src/sdio/native_sdio/src/hif.c b/hif/src/sdio/native_sdio/src/hif.c
index 926067c..7100baf 100644
--- a/hif/src/sdio/native_sdio/src/hif.c
+++ b/hif/src/sdio/native_sdio/src/hif.c
@@ -23,7 +23,6 @@
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sd.h>
-#include <linux/kthread.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <qdf_atomic.h>
@@ -38,26 +37,10 @@
 #include "hif_internal.h"
 #include <transfer/transfer.h>
 
-/* by default setup a bounce buffer for the data packets,
- * if the underlying host controller driver
- * does not use DMA you may be able to skip this step
- * and save the memory allocation and transfer time
- */
 #define HIF_USE_DMA_BOUNCE_BUFFER 1
 #define ATH_MODULE_NAME hif
 #include "a_debug.h"
 
-#if HIF_USE_DMA_BOUNCE_BUFFER
-/* macro to check if DMA buffer is WORD-aligned and DMA-able.
- * Most host controllers assume the
- * buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack).
- * virt_addr_valid check fails on stack memory.
- */
-#define BUFFER_NEEDS_BOUNCE(buffer)  (((unsigned long)(buffer) & 0x3) || \
-					!virt_addr_valid((buffer)))
-#else
-#define BUFFER_NEEDS_BOUNCE(buffer)   (false)
-#endif
 #define MAX_HIF_DEVICES 2
 #ifdef HIF_MBOX_SLEEP_WAR
 #define HIF_MIN_SLEEP_INACTIVITY_TIME_MS     50
@@ -83,7 +66,8 @@
 
 #define dev_to_sdio_func(d)		container_of(d, struct sdio_func, dev)
 #define to_sdio_driver(d)		container_of(d, struct sdio_driver, drv)
-static struct hif_sdio_dev *add_hif_device(struct sdio_func *func);
+static struct hif_sdio_dev *add_hif_device(struct hif_softc *hif_ctx,
+					   struct sdio_func *func);
 static void del_hif_device(struct hif_sdio_dev *device);
 
 int reset_sdio_on_unload;
@@ -172,186 +156,6 @@
 #endif
 
 /**
- * __hif_read_write() - sdio read/write wrapper
- * @device: pointer to hif device structure
- * @address: address to read
- * @buffer: buffer to hold read/write data
- * @length: length to read/write
- * @request: read/write/sync/async request
- * @context: pointer to hold calling context
- *
- * Return: 0 on success, error number otherwise.
- */
-static QDF_STATUS
-__hif_read_write(struct hif_sdio_dev *device,
-		 uint32_t address, char *buffer,
-		 uint32_t length, uint32_t request, void *context)
-{
-	uint8_t opcode;
-	QDF_STATUS status = QDF_STATUS_SUCCESS;
-	int ret = A_OK;
-	uint8_t *tbuffer;
-	bool bounced = false;
-
-	if (!device) {
-		HIF_ERROR("%s: device null!", __func__);
-		return QDF_STATUS_E_INVAL;
-	}
-
-	if (!device->func) {
-		HIF_ERROR("%s: func null!", __func__);
-		return QDF_STATUS_E_INVAL;
-	}
-
-	HIF_INFO_HI("%s: addr:0X%06X, len:%08d, %s, %s", __func__,
-		    address, length,
-		    request & HIF_SDIO_READ ? "Read " : "Write",
-		    request & HIF_ASYNCHRONOUS ? "Async" : "Sync ");
-
-	do {
-		if (request & HIF_EXTENDED_IO) {
-			HIF_INFO_HI("%s: Command type: CMD53\n", __func__);
-		} else {
-			HIF_ERROR("%s: Invalid command type: 0x%08x\n",
-				  __func__, request);
-			status = QDF_STATUS_E_INVAL;
-			break;
-		}
-
-		if (request & HIF_BLOCK_BASIS) {
-			/* round to whole block length size */
-			length =
-				(length / HIF_BLOCK_SIZE) *
-				HIF_BLOCK_SIZE;
-			HIF_INFO_HI("%s: Block mode (BlockLen: %d)\n",
-				    __func__, length);
-		} else if (request & HIF_BYTE_BASIS) {
-			HIF_INFO_HI("%s: Byte mode (BlockLen: %d)\n",
-				    __func__, length);
-		} else {
-			HIF_ERROR("%s: Invalid data mode: 0x%08x\n",
-				  __func__, request);
-			status = QDF_STATUS_E_INVAL;
-			break;
-		}
-		if (request & HIF_SDIO_WRITE) {
-			hif_fixup_write_param(device, request,
-					      &length, &address);
-
-			HIF_INFO_HI("addr:%08X, len:0x%08X, dummy:0x%04X\n",
-				    address, length,
-				    (request & HIF_DUMMY_SPACE_MASK) >> 16);
-		}
-
-		if (request & HIF_FIXED_ADDRESS) {
-			opcode = CMD53_FIXED_ADDRESS;
-			HIF_INFO_HI("%s: Addr mode: fixed 0x%X\n",
-				    __func__, address);
-		} else if (request & HIF_INCREMENTAL_ADDRESS) {
-			opcode = CMD53_INCR_ADDRESS;
-			HIF_INFO_HI("%s: Address mode: Incremental 0x%X\n",
-				    __func__, address);
-		} else {
-			HIF_ERROR("%s: Invalid address mode: 0x%08x\n",
-				  __func__, request);
-			status = QDF_STATUS_E_INVAL;
-			break;
-		}
-
-		if (request & HIF_SDIO_WRITE) {
-#if HIF_USE_DMA_BOUNCE_BUFFER
-			if (BUFFER_NEEDS_BOUNCE(buffer)) {
-				AR_DEBUG_ASSERT(device->dma_buffer);
-				tbuffer = device->dma_buffer;
-				/* copy the write data to the dma buffer */
-				AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
-				if (length > HIF_DMA_BUFFER_SIZE) {
-					HIF_ERROR("%s: Invalid write len: %d\n",
-						  __func__, length);
-					status = QDF_STATUS_E_INVAL;
-					break;
-				}
-				memcpy(tbuffer, buffer, length);
-				bounced = true;
-			} else {
-				tbuffer = buffer;
-			}
-#else
-			tbuffer = buffer;
-#endif
-			if (opcode == CMD53_FIXED_ADDRESS  && tbuffer) {
-				ret = sdio_writesb(device->func, address,
-						   tbuffer, length);
-				HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
-					    __func__, ret, address, length,
-					    *(int *)tbuffer);
-			} else if (tbuffer) {
-				ret = sdio_memcpy_toio(device->func, address,
-						       tbuffer, length);
-				HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
-					    __func__, ret, address, length,
-					    *(int *)tbuffer);
-			}
-		} else if (request & HIF_SDIO_READ) {
-#if HIF_USE_DMA_BOUNCE_BUFFER
-			if (BUFFER_NEEDS_BOUNCE(buffer)) {
-				AR_DEBUG_ASSERT(device->dma_buffer);
-				AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
-				if (length > HIF_DMA_BUFFER_SIZE) {
-					AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
-					("%s: Invalid read length: %d\n",
-					__func__, length));
-					status = QDF_STATUS_E_INVAL;
-					break;
-				}
-				tbuffer = device->dma_buffer;
-				bounced = true;
-			} else {
-				tbuffer = buffer;
-			}
-#else
-			tbuffer = buffer;
-#endif
-			if (opcode == CMD53_FIXED_ADDRESS && tbuffer) {
-				ret = sdio_readsb(device->func, tbuffer,
-						  address, length);
-				HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
-					    __func__, ret, address, length,
-					    *(int *)tbuffer);
-			} else if (tbuffer) {
-				ret = sdio_memcpy_fromio(device->func,
-							 tbuffer, address,
-							 length);
-				HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
-					    __func__, ret, address, length,
-					    *(int *)tbuffer);
-			}
-#if HIF_USE_DMA_BOUNCE_BUFFER
-			if (bounced && tbuffer)
-				memcpy(buffer, tbuffer, length);
-#endif
-		} else {
-			HIF_ERROR("%s: Invalid dir: 0x%08x", __func__, request);
-			status = QDF_STATUS_E_INVAL;
-			return status;
-		}
-
-		if (ret) {
-			HIF_ERROR("%s: SDIO bus operation failed!", __func__);
-			HIF_ERROR("%s: MMC stack returned : %d", __func__, ret);
-			HIF_ERROR("%s: addr:0X%06X, len:%08d, %s, %s",
-				  __func__, address, length,
-				  request & HIF_SDIO_READ ? "Read " : "Write",
-				  request & HIF_ASYNCHRONOUS ?
-				  "Async" : "Sync");
-			status = QDF_STATUS_E_FAILURE;
-		}
-	} while (false);
-
-	return status;
-}
-
-/**
  * add_to_async_list() - add bus reqest to async task list
  * @device: pointer to hif device
  * @busrequest: pointer to type of bus request
@@ -380,222 +184,6 @@
 	qdf_spin_unlock_irqrestore(&device->asynclock);
 }
 
-/**
- * hif_read_write() - queue a read/write request
- * @device: pointer to hif device structure
- * @address: address to read
- * @buffer: buffer to hold read/write data
- * @length: length to read/write
- * @request: read/write/sync/async request
- * @context: pointer to hold calling context
- *
- * Return: 0 on success, error number otherwise.
- */
-QDF_STATUS
-hif_read_write(struct hif_sdio_dev *device,
-		uint32_t address,
-		char *buffer, uint32_t length,
-		uint32_t request, void *context)
-{
-	QDF_STATUS status = QDF_STATUS_SUCCESS;
-	struct bus_request *busrequest;
-
-	AR_DEBUG_ASSERT(device);
-	AR_DEBUG_ASSERT(device->func);
-	AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-			("%s: device 0x%pK addr 0x%X buffer 0x%pK len %d req 0x%X context 0x%pK",
-			 __func__, device, address, buffer,
-			 length, request, context));
-
-	/*sdio r/w action is not needed when suspend, so just return */
-	if ((device->is_suspend == true)
-	    && (device->power_config == HIF_DEVICE_POWER_CUT)) {
-		AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("skip io when suspending\n"));
-		return QDF_STATUS_SUCCESS;
-	}
-	do {
-		if ((request & HIF_ASYNCHRONOUS) ||
-			(request & HIF_SYNCHRONOUS)) {
-			/* serialize all requests through the async thread */
-			AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-					("%s: Execution mode: %s\n", __func__,
-					 (request & HIF_ASYNCHRONOUS) ? "Async"
-					 : "Synch"));
-			busrequest = hif_allocate_bus_request(device);
-			if (!busrequest) {
-				AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
-					("no async bus requests available (%s, addr:0x%X, len:%d)\n",
-					 request & HIF_SDIO_READ ? "READ" :
-					 "WRITE", address, length));
-				return QDF_STATUS_E_FAILURE;
-			}
-			busrequest->address = address;
-			busrequest->buffer = buffer;
-			busrequest->length = length;
-			busrequest->request = request;
-			busrequest->context = context;
-
-			add_to_async_list(device, busrequest);
-
-			if (request & HIF_SYNCHRONOUS) {
-				AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-					("%s: queued sync req: 0x%lX\n",
-					 __func__, (unsigned long)busrequest));
-
-				/* wait for completion */
-				up(&device->sem_async);
-				if (down_interruptible(&busrequest->sem_req) !=
-				    0) {
-					/* interrupted, exit */
-					return QDF_STATUS_E_FAILURE;
-				} else {
-					QDF_STATUS status = busrequest->status;
-
-					AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-				    ("%s: sync return freeing 0x%lX: 0x%X\n",
-						 __func__,
-						 (unsigned long)
-						 busrequest,
-						 busrequest->status));
-					AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-						("%s: freeing req: 0x%X\n",
-						 __func__,
-						 (unsigned int)
-						 request));
-					hif_free_bus_request(device,
-						busrequest);
-					return status;
-				}
-			} else {
-				AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-					("%s: queued async req: 0x%lX\n",
-						__func__,
-						 (unsigned long)busrequest));
-				up(&device->sem_async);
-				return QDF_STATUS_E_PENDING;
-			}
-		} else {
-			AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
-				("%s: Invalid execution mode: 0x%08x\n",
-					__func__,
-					 (unsigned int)request));
-			status = QDF_STATUS_E_INVAL;
-			break;
-		}
-	} while (0);
-
-	return status;
-}
-
-/**
- * async_task() - thread function to serialize all bus requests
- * @param: pointer to hif device
- *
- * thread function to serialize all requests, both sync and async
- * Return: 0 on success, error number otherwise.
- */
-static int async_task(void *param)
-{
-	struct hif_sdio_dev *device;
-	struct bus_request *request;
-	QDF_STATUS status;
-	bool claimed = false;
-
-	device = (struct hif_sdio_dev *) param;
-	set_current_state(TASK_INTERRUPTIBLE);
-	while (!device->async_shutdown) {
-		/* wait for work */
-		if (down_interruptible(&device->sem_async) != 0) {
-			/* interrupted, exit */
-			AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-					("%s: async task interrupted\n",
-					 __func__));
-			break;
-		}
-		if (device->async_shutdown) {
-			AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-					("%s: async task stopping\n",
-					 __func__));
-			break;
-		}
-		/* we want to hold the host over multiple cmds
-		 * if possible, but holding the host blocks
-		 * card interrupts
-		 */
-		qdf_spin_lock_irqsave(&device->asynclock);
-		/* pull the request to work on */
-		while (device->asyncreq) {
-			request = device->asyncreq;
-			if (request->inusenext)
-				device->asyncreq = request->inusenext;
-			else
-				device->asyncreq = NULL;
-			qdf_spin_unlock_irqrestore(&device->asynclock);
-			AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-				("%s: async_task processing req: 0x%lX\n",
-				 __func__, (unsigned long)request));
-
-			if (!claimed) {
-				sdio_claim_host(device->func);
-				claimed = true;
-			}
-			if (request->scatter_req) {
-				A_ASSERT(device->scatter_enabled);
-				/* pass the request to scatter routine which
-				 * executes it synchronously, note, no need
-				 * to free the request since scatter requests
-				 * are maintained on a separate list
-				 */
-				status = do_hif_read_write_scatter(device,
-							request);
-			} else {
-				/* call hif_read_write in sync mode */
-				status =
-					__hif_read_write(device,
-							 request->address,
-							 request->buffer,
-							 request->length,
-							 request->
-							 request &
-							 ~HIF_SYNCHRONOUS,
-							 NULL);
-				if (request->request & HIF_ASYNCHRONOUS) {
-					void *context = request->context;
-
-					AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-					("%s: freeing req: 0x%lX\n",
-						 __func__, (unsigned long)
-						 request));
-					hif_free_bus_request(device, request);
-					AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-				      ("%s: async_task completion req 0x%lX\n",
-						 __func__, (unsigned long)
-						 request));
-					device->htc_callbacks.
-					rw_compl_handler(context, status);
-				} else {
-					AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
-				      ("%s: async_task upping req: 0x%lX\n",
-						 __func__, (unsigned long)
-						 request));
-					request->status = status;
-					up(&request->sem_req);
-				}
-			}
-			qdf_spin_lock_irqsave(&device->asynclock);
-		}
-		qdf_spin_unlock_irqrestore(&device->asynclock);
-		if (claimed) {
-			sdio_release_host(device->func);
-			claimed = false;
-		}
-	}
-
-	complete_and_exit(&device->async_completion, 0);
-
-	return 0;
-}
-
 /*
  * Setup IRQ mode for deep sleep and WoW
  * Switch back to 1 bits mode when we suspend for
@@ -603,6 +191,7 @@
  * Re-enable async 4-bit irq mode for some host controllers
  * after resume.
  */
+#ifdef CONFIG_SDIO_TRANSFER_MAILBOX
 static int sdio_enable4bits(struct hif_sdio_dev *device, int enable)
 {
 	int ret = 0;
@@ -675,34 +264,12 @@
 
 	return ret;
 }
-
-static QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
-				   struct sdio_func *func,
-				   bool reset)
+#else
+static int sdio_enable4bits(struct hif_sdio_dev *device, int enable)
 {
-	QDF_STATUS status = QDF_STATUS_SUCCESS;
-
-	HIF_ENTER();
-	device = get_hif_device(func);
-	if (!IS_ERR(device->async_task)) {
-		init_completion(&device->async_completion);
-		device->async_shutdown = 1;
-		up(&device->sem_async);
-		wait_for_completion(&device->async_completion);
-		device->async_task = NULL;
-		sema_init(&device->sem_async, 0);
-	}
-
-	status = hif_sdio_func_disable(device, func, reset);
-	if (status == QDF_STATUS_SUCCESS)
-		device->is_disabled = true;
-
-	cleanup_hif_scatter_resources(device);
-
-	HIF_EXIT();
-
-	return status;
+	return 0;
 }
+#endif
 
 /**
  * hif_sdio_probe() - configure sdio device
@@ -712,9 +279,9 @@
  *
  * Return: 0 for success and non-zero for failure
  */
-static A_STATUS hif_sdio_probe(struct hif_softc *ol_sc,
-			       struct sdio_func *func,
-			       struct hif_sdio_dev *device)
+A_STATUS hif_sdio_probe(struct hif_softc *ol_sc,
+			struct sdio_func *func,
+			struct hif_sdio_dev *device)
 {
 	int ret = 0;
 	const struct sdio_device_id *id;
@@ -794,7 +361,9 @@
 		goto err_attach1;
 	}
 
-	return 0;
+	ret = hif_dev_register_channels(device, func);
+
+	return ret;
 
 err_attach1:
 	if (scn->ramdump_base)
@@ -803,48 +372,9 @@
 	return ret;
 }
 
-static QDF_STATUS hif_enable_func(struct hif_softc *ol_sc,
-				  struct hif_sdio_dev *device,
-				  struct sdio_func *func,
-				  bool resume)
-{
-	int ret = QDF_STATUS_SUCCESS;
-
-	HIF_ENTER();
-
-	if (!device) {
-		HIF_ERROR("%s: HIF device is NULL", __func__);
-		return QDF_STATUS_E_INVAL;
-	}
-
-	if (hif_sdio_func_enable(device, func))
-		return QDF_STATUS_E_FAILURE;
-
-	/* create async I/O thread */
-	if (!device->async_task && device->is_disabled) {
-		device->async_shutdown = 0;
-		device->async_task = kthread_create(async_task,
-						    (void *)device,
-						    "AR6K Async");
-		if (IS_ERR(device->async_task)) {
-			HIF_ERROR("%s: Error creating async task",
-				  __func__);
-			return QDF_STATUS_E_FAILURE;
-		}
-		device->is_disabled = false;
-		wake_up_process(device->async_task);
-	}
-
-	if (resume == false)
-		ret = hif_sdio_probe(ol_sc, func, device);
-
-	HIF_EXIT();
-
-	return ret;
-}
-
 /**
  * power_state_change_notify() - SDIO bus power notification handler
+ * @ol_sc: HIF device context
  * @config: hif device power change type
  *
  * Return: 0 on success, error number otherwise.
@@ -910,6 +440,7 @@
 
 /**
  * hif_configure_device() - configure sdio device
+ * @ol_sc: HIF device context
  * @device: pointer to hif device structure
  * @opcode: configuration type
  * @config: configuration value to set
@@ -1032,6 +563,7 @@
 
 /**
  * hif_device_inserted() - hif-sdio driver probe handler
+ * @ol_sc: HIF device context
  * @func: pointer to sdio_func
  * @id: pointer to sdio_device_id
  *
@@ -1057,10 +589,10 @@
 		if (hifdevice &&
 		    hifdevice->power_config == HIF_DEVICE_POWER_CUT &&
 		    hifdevice->host == func->card->host) {
-			device = get_hif_device(func);
+			device = get_hif_device(ol_sc, func);
 			hifdevice->func = func;
 			hifdevice->power_config = HIF_DEVICE_POWER_UP;
-			hif_sdio_set_drvdata(func, hifdevice);
+			hif_sdio_set_drvdata(ol_sc, func, hifdevice);
 
 			if (device->is_suspend) {
 				HIF_INFO("%s: Resume from suspend", __func__);
@@ -1072,9 +604,10 @@
 
 	/* If device not found, then it is a new insertion, alloc and add it */
 	if (!device) {
-		if (add_hif_device(func) == NULL)
+		if (!add_hif_device(ol_sc, func))
 			return QDF_STATUS_E_FAILURE;
-		device = get_hif_device(func);
+
+		device = get_hif_device(ol_sc, func);
 
 		for (i = 0; i < MAX_HIF_DEVICES; ++i) {
 			if (!hif_devices[i]) {
@@ -1095,13 +628,13 @@
 		 */
 		sdio_claim_host(func);
 
-		hif_sdio_quirk_force_drive_strength(func);
+		hif_sdio_quirk_force_drive_strength(ol_sc, func);
 
-		hif_sdio_quirk_write_cccr(func);
+		hif_sdio_quirk_write_cccr(ol_sc, func);
 
-		ret = hif_sdio_set_bus_speed(func);
+		ret = hif_sdio_set_bus_speed(ol_sc, func);
 
-		ret = hif_sdio_set_bus_width(func);
+		ret = hif_sdio_set_bus_width(ol_sc, func);
 		if (debugcccr)
 			hif_dump_cccr(device);
 
@@ -1174,11 +707,11 @@
  * @pdev - HIF layer object
  * @func - SDIO bus function object
  *
- * Return - NONE
+ * Return - error in case of failure to configure, else success
  */
-void hif_sdio_configure_pipes(struct hif_sdio_dev *dev, struct sdio_func *func)
+int hif_sdio_configure_pipes(struct hif_sdio_dev *dev, struct sdio_func *func)
 {
-	/* ADMA-TODO */
+	return hif_dev_configure_pipes(dev, func);
 }
 
 /**
@@ -1233,7 +766,7 @@
 int hif_device_suspend(struct hif_softc *ol_sc, struct device *dev)
 {
 	struct sdio_func *func = dev_to_sdio_func(dev);
-	struct hif_sdio_dev *device = get_hif_device(func);
+	struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
 	mmc_pm_flag_t pm_flag = 0;
 	enum HIF_DEVICE_POWER_CHANGE_TYPE config;
 	struct mmc_host *host = func->card->host;
@@ -1314,7 +847,7 @@
 	enum HIF_DEVICE_POWER_CHANGE_TYPE config;
 	struct hif_sdio_dev *device;
 
-	device = get_hif_device(func);
+	device = get_hif_device(ol_sc, func);
 	if (!device) {
 		HIF_ERROR("%s: hif object is null", __func__);
 		return -EINVAL;
@@ -1367,7 +900,8 @@
 
 	return 0;
 }
-static void hif_device_removed(struct sdio_func *func)
+
+static void hif_device_removed(struct hif_softc *ol_sc, struct sdio_func *func)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct hif_sdio_dev *device;
@@ -1375,7 +909,7 @@
 
 	AR_DEBUG_ASSERT(func);
 	HIF_ENTER();
-	device = get_hif_device(func);
+	device = get_hif_device(ol_sc, func);
 
 	if (device->power_config == HIF_DEVICE_POWER_CUT) {
 		device->func = NULL;    /* func will be free by mmc stack */
@@ -1406,7 +940,8 @@
 	HIF_EXIT();
 }
 
-static struct hif_sdio_dev *add_hif_device(struct sdio_func *func)
+static struct hif_sdio_dev *add_hif_device(struct hif_softc *ol_sc,
+					   struct sdio_func *func)
 {
 	struct hif_sdio_dev *hifdevice = NULL;
 	int ret = 0;
@@ -1430,8 +965,8 @@
 	hifdevice->func = func;
 	hifdevice->power_config = HIF_DEVICE_POWER_UP;
 	hifdevice->device_state = HIF_DEVICE_STATE_ON;
-	ret = hif_sdio_set_drvdata(func, hifdevice);
-	hif_info("status %d", ret);
+	ret = hif_sdio_set_drvdata(ol_sc, func, hifdevice);
+	HIF_INFO("status %d", ret);
 
 	return hifdevice;
 }
@@ -1552,12 +1087,12 @@
 
 	HIF_ERROR("%s: Enter", __func__);
 	status = hif_device_inserted(ol_sc, func, id);
-	HIF_ERROR("%s: Exit", __func__);
+	HIF_ERROR("%s: Exit: status:%d", __func__, status);
 
 	return status;
 }
 
-void hif_sdio_device_removed(struct sdio_func *func)
+void hif_sdio_device_removed(struct hif_softc *ol_sc, struct sdio_func *func)
 {
-	hif_device_removed(func);
+	hif_device_removed(ol_sc, func);
 }
diff --git a/hif/src/sdio/transfer/adma.c b/hif/src/sdio/transfer/adma.c
new file mode 100644
index 0000000..3526ee9
--- /dev/null
+++ b/hif/src/sdio/transfer/adma.c
@@ -0,0 +1,858 @@
+/*
+ * Copyright (c) 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <qdf_lock.h>
+#include "adma.h"
+#include "hif_sdio_internal.h"
+#include "pld_sdio.h"
+#include "if_sdio.h"
+
+/**
+ * hif_dev_get_fifo_address() - get the fifo addresses for dma
+ * @pdev:  SDIO HIF object
+ * @c : FIFO address config pointer
+ *
+ * Return : 0 for success, non-zero for error
+ */
+int hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
+			     void *c,
+			     uint32_t config_len)
+{
+	/* SDIO AL handles DMA Addresses */
+	return 0;
+}
+
+/**
+ * hif_dev_get_block_size() - get the adma block size for dma
+ * @config : block size config pointer
+ *
+ * Return : NONE
+ */
+void hif_dev_get_block_size(void *config)
+{
+	/* TODO Get block size used by AL Layer in Mission ROM Mode */
+	*((uint32_t *)config) = HIF_BLOCK_SIZE; /* QCN_SDIO_MROM_BLK_SZ TODO */
+}
+
+/**
+ * hif_dev_configure_pipes() - configure pipes
+ * @pdev: SDIO HIF object
+ * @func: sdio function object
+ *
+ * Return : 0 for success, non-zero for error
+ */
+int hif_dev_configure_pipes(struct hif_sdio_dev *pdev, struct sdio_func *func)
+{
+	/* SDIO AL Configures SDIO Channels */
+	return 0;
+}
+
+/** hif_dev_set_mailbox_swap() - Set the mailbox swap
+ * @pdev : The HIF layer object
+ *
+ * Return: none
+ */
+void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev)
+{
+	/* SDIO AL doesn't use mailbox architecture */
+}
+
+/** hif_dev_get_mailbox_swap() - Get the mailbox swap setting
+ * @pdev : The HIF layer object
+ *
+ * Return: true or false
+ */
+bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev)
+{
+	/* SDIO AL doesn't use mailbox architecture */
+	return false;
+}
+
+/**
+ * hif_dev_dsr_handler() - Synchronous interrupt handler
+ *
+ * @context: hif send context
+ *
+ * Return: 0 for success and non-zero for failure
+ */
+QDF_STATUS hif_dev_dsr_handler(void *context)
+{
+	/* SDIO AL handles interrupts */
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * hif_dev_map_service_to_pipe() - maps ul/dl pipe to service id.
+ * @pDev: SDIO HIF object
+ * @ServiceId: sevice index
+ * @ULPipe: uplink pipe id
+ * @DLPipe: down-linklink pipe id
+ *
+ * Return: 0 on success, error value on invalid map
+ */
+QDF_STATUS hif_dev_map_service_to_pipe(struct hif_sdio_dev *pdev, uint16_t svc,
+				       uint8_t *ul_pipe, uint8_t *dl_pipe)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	switch (svc) {
+	case HTT_DATA_MSG_SVC:
+		*dl_pipe = 2;
+		*ul_pipe = 3;
+		break;
+
+	case HTC_CTRL_RSVD_SVC:
+	case HTC_RAW_STREAMS_SVC:
+		*dl_pipe = 0;
+		*ul_pipe = 1;
+		break;
+
+	case WMI_DATA_BE_SVC:
+	case WMI_DATA_BK_SVC:
+	case WMI_DATA_VI_SVC:
+	case WMI_DATA_VO_SVC:
+		*dl_pipe = 2;
+		*ul_pipe = 3;
+		break;
+
+	case WMI_CONTROL_SVC:
+		*dl_pipe = 0;
+		*ul_pipe = 1;
+		break;
+
+	default:
+		HIF_ERROR("%s: Err : Invalid service (%d)",
+			  __func__, svc);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+	return status;
+}
+
+/** hif_dev_setup_device() - Setup device specific stuff here required for hif
+ * @pdev : HIF layer object
+ *
+ * return 0 on success, error otherwise
+ */
+int hif_dev_setup_device(struct hif_sdio_device *pdev)
+{
+	hif_dev_get_block_size(&pdev->BlockSize);
+
+	return 0;
+}
+
+/** hif_dev_mask_interrupts() - Disable the interrupts in the device
+ * @pdev SDIO HIF Object
+ *
+ * Return: NONE
+ */
+void hif_dev_mask_interrupts(struct hif_sdio_device *pdev)
+{
+	/* SDIO AL Handles Interrupts */
+}
+
+/** hif_dev_unmask_interrupts() - Enable the interrupts in the device
+ * @pdev SDIO HIF Object
+ *
+ * Return: NONE
+ */
+void hif_dev_unmask_interrupts(struct hif_sdio_device *pdev)
+{
+	/* SDIO AL Handles Interrupts */
+}
+
+/**
+ * hif_dev_map_pipe_to_adma_chan() - maps pipe id to adma chan
+ * @pdev: The pointer to the hif device object
+ * @pipeid: pipe index
+ *
+ * Return: adma channel handle
+ */
+struct sdio_al_channel_handle *hif_dev_map_pipe_to_adma_chan
+(
+struct hif_sdio_device *dev,
+uint8_t pipeid
+)
+{
+	struct hif_sdio_dev *pdev = dev->HIFDevice;
+
+	HIF_ENTER();
+
+	if ((pipeid == 0) || (pipeid == 1))
+		return pdev->al_chan[0];
+	else if ((pipeid == 2) || (pipeid == 3))
+		return pdev->al_chan[1];
+	else
+		return NULL;
+}
+
+/**
+ * hif_dev_map_adma_chan_to_pipe() - map adma chan to htc pipe
+ * @pdev: The pointer to the hif device object
+ * @chan: channel number
+ * @upload: boolean to decide upload or download
+ *
+ * Return: Invalid pipe index
+ */
+uint8_t hif_dev_map_adma_chan_to_pipe(struct hif_sdio_device *pdev,
+				      uint8_t chan, bool upload)
+{
+	HIF_INFO("%s: chan: %u, %s", __func__, chan,
+		 upload ? "Upload" : "Download");
+
+	if (chan == 0) /* chan 0 is mapped to HTT */
+		return upload ? 1 : 0;
+	else if (chan == 1) /* chan 1 is mapped to WMI */
+		return upload ? 3 : 2;
+
+	return (uint8_t)-1; /* invalid channel id */
+}
+
+/**
+ * hif_get_send_address() - Get the transfer pipe address
+ * @pdev: The pointer to the hif device object
+ * @pipe: The pipe identifier
+ *
+ * Return 0 for success and non-zero for failure to map
+ */
+int hif_get_send_address(struct hif_sdio_device *pdev,
+			 uint8_t pipe, unsigned long *addr)
+{
+	struct sdio_al_channel_handle *chan = NULL;
+
+	HIF_INFO("pipe: %u", pipe);
+
+	if (!addr)
+		return -EINVAL;
+
+	*addr = 0;
+	chan = hif_dev_map_pipe_to_adma_chan(pdev, pipe);
+
+	if (!chan)
+		return -EINVAL;
+
+	*addr = (unsigned long)chan;
+
+	return 0;
+}
+
+/**
+ * hif_fixup_write_param() - Tweak the address and length parameters
+ * @pdev: The pointer to the hif device object
+ * @length: The length pointer
+ * @addr: The addr pointer
+ *
+ * Return: None
+ */
+void hif_fixup_write_param(struct hif_sdio_dev *pdev, uint32_t req,
+			   uint32_t *length, uint32_t *addr)
+{
+	HIF_ENTER();
+	/* ADMA-TODO */
+	HIF_EXIT();
+}
+
+#define HIF_MAX_RX_Q_ALLOC 0 /* TODO */
+#define HIF_RX_Q_ALLOC_THRESHOLD 100
+QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
+			    struct sdio_func *func,
+			    bool reset)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+#if HIF_MAX_RX_Q_ALLOC
+	qdf_list_node_t *node;
+	struct rx_q_entry *rx_q_elem;
+#endif
+	HIF_ENTER();
+
+#if HIF_MAX_RX_Q_ALLOC
+	qdf_spin_lock_irqsave(&device->rx_q_lock);
+
+	for (; device->rx_q.count; ) {
+		qdf_list_remove_back(&device->rx_q, &node);
+		rx_q_elem = container_of(node, struct rx_q_entry, entry);
+		if (rx_q_elem) {
+			if (rx_q_elem->nbuf)
+				qdf_nbuf_free(rx_q_elem->nbuf);
+			qdf_mem_free(rx_q_elem);
+		}
+	}
+	qdf_destroy_work(0, &device->rx_q_alloc_work);
+
+	qdf_spin_unlock_irqrestore(&device->rx_q_lock);
+
+	qdf_spinlock_destroy(&device->rx_q_lock);
+#endif
+
+	status = hif_sdio_func_disable(device, func, reset);
+	if (status == QDF_STATUS_SUCCESS)
+		device->is_disabled = true;
+
+	cleanup_hif_scatter_resources(device);
+
+	HIF_EXIT();
+
+	return status;
+}
+
+/**
+ * hif_enable_func() - Enable SDIO function
+ *
+ * @ol_sc: HIF object pointer
+ * @device: HIF device pointer
+ * @sdio_func: SDIO function pointer
+ * @resume: If this is called from resume or probe
+ *
+ * Return: 0 in case of success, else error value
+ */
+QDF_STATUS hif_enable_func(struct hif_softc *ol_sc, struct hif_sdio_dev *device,
+			   struct sdio_func *func, bool resume)
+{
+	int ret = QDF_STATUS_SUCCESS;
+
+	if (!device) {
+		HIF_ERROR("%s: HIF device is NULL", __func__);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!resume)
+		ret = hif_sdio_probe(ol_sc, func, device);
+
+#if HIF_MAX_RX_Q_ALLOC
+	if (!ret) {
+		qdf_list_create(&device->rx_q, HIF_MAX_RX_Q_ALLOC);
+		qdf_spinlock_create(&device->rx_q_lock);
+		qdf_create_work(0, &device->rx_q_alloc_work,
+				hif_sdio_rx_q_alloc, (void *)device);
+		device->rx_q_alloc_work_scheduled = true;
+		qdf_sched_work(0, &device->rx_q_alloc_work);
+	}
+#endif
+	return ret;
+}
+
+/**
+ * hif_sdio_get_net_buf() - Get a network buffer from the rx q
+ * @dev - HIF device object
+ *
+ * Return - NULL if out of buffers, else qdf_nbuf_t
+ */
+#define HEAD_ROOM 256
+#define len_head_room(len) ((len) + HEAD_ROOM)
+#define is_pad_block(buf) (*((uint32_t *)buf) == 0xbabababa)
+#if HIF_MAX_RX_Q_ALLOC
+qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev)
+{
+	qdf_list_node_t *node;
+	qdf_nbuf_t nbuf = NULL;
+	qdf_list_t *q = &dev->rx_q;
+	struct rx_q_entry *elem = NULL;
+
+	qdf_spin_lock_irqsave(&dev->rx_q_lock);
+
+	if (q->count) {
+		qdf_list_remove_front(q, &node);
+		elem = qdf_container_of(node, struct rx_q_entry, entry);
+		nbuf = elem->nbuf;
+	} else {
+		HIF_ERROR("%s: no rx q elements", __func__);
+	}
+
+	if (q->count <= HIF_RX_Q_ALLOC_THRESHOLD &&
+	    !dev->rx_q_alloc_work_scheduled) {
+		dev->rx_q_alloc_work_scheduled = true;
+		qdf_sched_work(0, &dev->rx_q_alloc_work);
+	}
+
+	qdf_spin_unlock_irqrestore(&dev->rx_q_lock);
+
+	qdf_mem_free(elem);
+
+	return nbuf;
+}
+#else
+qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev)
+{
+	qdf_nbuf_t nbuf;
+
+	nbuf = qdf_nbuf_alloc(NULL, HIF_SDIO_RX_BUFFER_SIZE + HEAD_ROOM,
+			      HEAD_ROOM, 4, 0);
+	return nbuf;
+}
+#endif
+/**
+ * hif_sdio_rx_q_alloc() - Deferred work for pre-alloc rx q
+ * @ctx - Pointer to context object
+ *
+ * Return NONE
+ */
+#if HIF_MAX_RX_Q_ALLOC
+void hif_sdio_rx_q_alloc(void *ctx)
+{
+	struct rx_q_entry *rx_q_elem;
+	struct hif_sdio_dev *dev = (struct hif_sdio_dev *)ctx;
+	unsigned int rx_q_count = dev->rx_q.count;
+
+	HIF_ENTER();
+	qdf_spin_lock_irqsave(&dev->rx_q_lock);
+
+	for (; rx_q_count < dev->rx_q.max_size; rx_q_count++) {
+		rx_q_elem = qdf_mem_malloc(sizeof(struct rx_q_entry));
+		if (!rx_q_elem) {
+			HIF_ERROR("%s: failed to alloc rx q elem", __func__);
+			break;
+		}
+
+		rx_q_elem->nbuf = qdf_nbuf_alloc(NULL, HIF_SDIO_RX_BUFFER_SIZE +
+						 HEAD_ROOM, HEAD_ROOM, 4, 0);
+		if (!rx_q_elem->nbuf) {
+			HIF_ERROR("%s: failed to alloc nbuf for rx", __func__);
+			qdf_mem_free(rx_q_elem);
+			break;
+		}
+
+		qdf_list_insert_back(&dev->rx_q, &rx_q_elem->entry);
+	}
+	dev->rx_q_alloc_work_scheduled = false;
+
+	qdf_spin_unlock_irqrestore(&dev->rx_q_lock);
+	HIF_EXIT();
+}
+#else
+void hif_sdio_rx_q_alloc(void *ctx)
+{
+}
+#endif
+
+#include <linux/qcn_sdio_al.h>
+
+struct sdio_al_channel_data qcn7605_chan[HIF_SDIO_MAX_AL_CHANNELS] = {
+	{
+		.name = "SDIO_AL_WLAN_CH0", /* HTT */
+		.client_data = NULL, /* populate from client handle */
+		.ul_xfer_cb = ul_xfer_cb,
+		.dl_xfer_cb = dl_xfer_cb,
+		.dl_data_avail_cb = dl_data_avail_cb,
+		.dl_meta_data_cb = NULL
+	},
+	{
+		.name = "SDIO_AL_WLAN_CH1", /* WMI */
+		.client_data = NULL, /* populate from client handle */
+		.ul_xfer_cb = ul_xfer_cb,
+		.dl_xfer_cb = dl_xfer_cb,
+		.dl_data_avail_cb = dl_data_avail_cb,
+		.dl_meta_data_cb = NULL
+	}
+};
+
+/**
+ * hif_dev_register_channels()- Register transport layer channels
+ * @dev  : HIF device object
+ * @func : SDIO function pointer
+ *
+ * Return : success on configuration, else failure
+ */
+int hif_dev_register_channels(struct hif_sdio_dev *dev, struct sdio_func *func)
+{
+	int ret = 0;
+	unsigned int chan;
+	struct sdio_al_channel_data *chan_data[HIF_ADMA_MAX_CHANS];
+
+	HIF_ENTER();
+
+	dev->al_client = pld_sdio_get_sdio_al_client_handle(func);
+	if (ret || !dev->al_client) {
+		HIF_ERROR("%s: Failed to get get sdio al handle", __func__);
+		return ret;
+	}
+
+	if ((func->device & MANUFACTURER_ID_AR6K_BASE_MASK) ==
+	    MANUFACTURER_ID_QCN7605_BASE) {
+		dev->adma_chans_used = 2;
+		qcn7605_chan[0].client_data = dev->al_client->client_data;
+		qcn7605_chan[1].client_data = dev->al_client->client_data;
+		chan_data[0] = &qcn7605_chan[0];
+		chan_data[1] = &qcn7605_chan[1];
+	} else {
+		dev->adma_chans_used = 0;
+	}
+
+	for (chan = 0; chan < dev->adma_chans_used; chan++) {
+		dev->al_chan[chan] =
+		pld_sdio_register_sdio_al_channel(dev->al_client,
+						  chan_data[chan]);
+		if (!dev->al_chan[chan] || IS_ERR(dev->al_chan[chan])) {
+			ret = -EINVAL;
+			HIF_ERROR("%s: Channel registration failed", __func__);
+		} else {
+			dev->al_chan[chan]->priv = (void *)dev;
+			HIF_INFO("%s: chan %s : id : %u", __func__,
+				 chan_data[chan]->name,
+				 dev->al_chan[chan]->channel_id);
+		}
+	}
+
+	HIF_EXIT();
+
+	return ret;
+}
+
+/**
+ * hif_dev_unregister_channels()- Register transport layer channels
+ * @dev  : HIF device object
+ * @func : SDIO Function pointer
+ *
+ * Return : None
+ */
+void hif_dev_unregister_channels(struct hif_sdio_dev *dev,
+				 struct sdio_func *func)
+{
+	unsigned int chan;
+
+	if (!dev) {
+		HIF_ERROR("%s: hif_sdio_dev is null", __func__);
+		return;
+	}
+
+	for (chan = 0; chan < dev->adma_chans_used; chan++) {
+		dev->al_chan[chan]->priv = NULL;
+		pld_sdio_unregister_sdio_al_channel(dev->al_chan[chan]);
+	}
+}
+
+/**
+ * hif_read_write() - queue a read/write request
+ * @dev: pointer to hif device structure
+ * @address: address to read, actually channel pointer
+ * @buffer: buffer to hold read/write data
+ * @length: length to read/write
+ * @request: read/write/sync/async request
+ * @context: pointer to hold calling context
+ *
+ * Return: 0, pending  on success, error number otherwise.
+ */
+QDF_STATUS
+hif_read_write(struct hif_sdio_dev *dev,
+	       unsigned long sdio_al_ch_handle,
+	       char *cbuffer, uint32_t length,
+	       uint32_t request, void *context)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct sdio_al_channel_handle *ch;
+	struct bus_request *bus_req;
+	enum sdio_al_dma_direction dir;
+	struct hif_sdio_device *device;
+	QDF_STATUS (*rx_comp)(void *, qdf_nbuf_t, uint8_t);
+	qdf_nbuf_t nbuf;
+	int ret = 0, payload_len = 0;
+	unsigned char *buffer = (unsigned char *)cbuffer;
+
+	if (!dev || !sdio_al_ch_handle) {
+		HIF_ERROR("%s: device = %pK, addr = %lu", __func__,
+			  dev, sdio_al_ch_handle);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!(request & HIF_ASYNCHRONOUS) &&
+	    !(request & HIF_SYNCHRONOUS)) {
+		HIF_ERROR("%s: Invalid request mode", __func__);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/*sdio r/w action is not needed when suspend, so just return */
+	if ((dev->is_suspend) &&
+	    (dev->power_config == HIF_DEVICE_POWER_CUT)) {
+		HIF_INFO("%s: skip in suspend", __func__);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	ch = (struct sdio_al_channel_handle *)sdio_al_ch_handle;
+
+	bus_req = hif_allocate_bus_request(dev);
+	if (!bus_req) {
+		HIF_ERROR("%s: Bus alloc failed", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	bus_req->address = sdio_al_ch_handle;
+	bus_req->length = length;
+	bus_req->request = request;
+	bus_req->context = context;
+	bus_req->buffer = buffer;
+
+	/* Request SDIO AL to do transfer */
+	dir = (request & HIF_SDIO_WRITE) ? SDIO_AL_TX : SDIO_AL_RX;
+
+	if (request & HIF_SDIO_WRITE)
+		HIF_TRACE("%s: Tx len %d", __func__, length);
+
+	if (request & HIF_SDIO_READ)
+		HIF_TRACE("%s: Rx len %d", __func__, length);
+
+	if (request & HIF_SYNCHRONOUS) {
+		ret = sdio_al_queue_transfer(ch,
+					     dir,
+					     bus_req->buffer,
+					     bus_req->length,
+					     1); /* higher priority */
+		if (ret) {
+			status = QDF_STATUS_E_FAILURE;
+			HIF_ERROR("%s: SYNC REQ failed ret=%d", __func__, ret);
+		} else {
+			status = QDF_STATUS_SUCCESS;
+		}
+
+		hif_free_bus_request(dev, bus_req);
+
+		if ((status == QDF_STATUS_SUCCESS) && (dir == SDIO_AL_RX)) {
+			nbuf = (qdf_nbuf_t)context;
+			payload_len = HTC_GET_FIELD(bus_req->buffer,
+						    HTC_FRAME_HDR,
+						    PAYLOADLEN);
+			qdf_nbuf_set_pktlen(nbuf, payload_len + HTC_HDR_LENGTH);
+			device = (struct hif_sdio_device *)dev->htc_context;
+			rx_comp = device->hif_callbacks.rxCompletionHandler;
+			rx_comp(device->hif_callbacks.Context, nbuf, 0);
+		}
+	} else {
+		ret = sdio_al_queue_transfer_async(ch,
+						   dir,
+						   bus_req->buffer,
+						   bus_req->length,
+						   1, /* higher priority */
+						   (void *)bus_req);
+		if (ret) {
+			status = QDF_STATUS_E_FAILURE;
+			HIF_ERROR("%s: ASYNC REQ fail ret=%d for len=%d ch=%d",
+				  __func__, ret, length, ch->channel_id);
+			hif_free_bus_request(dev, bus_req);
+		} else {
+			status = QDF_STATUS_E_PENDING;
+		}
+	}
+	return status;
+}
+
+/**
+ * ul_xfer_cb() - Completion call back for asyncronous transfer
+ * @ch_handle: The sdio al channel handle
+ * @result: The result of the operation
+ * @context: pointer to request context
+ *
+ * Return: None
+ */
+void ul_xfer_cb(struct sdio_al_channel_handle *ch_handle,
+		struct sdio_al_xfer_result *result,
+		void *ctx)
+{
+	struct bus_request *req = (struct bus_request *)ctx;
+	struct hif_sdio_dev *dev;
+
+	if (!ch_handle || !result) {
+		HIF_ERROR("%s: Invalid args", __func__);
+		qdf_assert_always(0);
+		return;
+	}
+
+	dev = (struct hif_sdio_dev *)ch_handle->priv;
+
+	if (result->xfer_status) {
+		req->status = QDF_STATUS_E_FAILURE;
+		HIF_ERROR("%s: ASYNC Tx failed status=%d", __func__,
+			  result->xfer_status);
+	} else {
+		req->status = QDF_STATUS_SUCCESS;
+	}
+
+	dev->htc_callbacks.rw_compl_handler(req->context, req->status);
+
+	hif_free_bus_request(dev, req);
+}
+
+/**
+ * dl_data_avail_cb() - Called when data is available on a channel
+ * @ch_handle: The sdio al channel handle
+ * @len: The len of data available to download
+ *
+ * Return: None
+ */
+/* Use the asynchronous method of transfer. This will help in
+ * completing READ in the transfer done callback later which
+ * runs in sdio al thread context. If we do the syncronous
+ * transfer here, the thread context won't be available and
+ * perhaps a new thread may be reaquired here.
+ */
+void dl_data_avail_cb(struct sdio_al_channel_handle *ch_handle,
+		      unsigned int len)
+{
+	struct hif_sdio_dev *dev;
+	unsigned int chan;
+	qdf_nbuf_t nbuf;
+
+	if (!ch_handle || !len) {
+		HIF_ERROR("%s: Invalid args %u", __func__, len);
+		qdf_assert_always(0);
+		return;
+	}
+
+	dev = (struct hif_sdio_dev *)ch_handle->priv;
+	chan = ch_handle->channel_id;
+
+	if (chan > HIF_SDIO_MAX_AL_CHANNELS) {
+		HIF_ERROR("%s: Invalid Ch ID %d", __func__, chan);
+		return;
+	}
+
+	/* allocate a buffer for reading the data from the chip.
+	 * Note that this is raw, unparsed buffer and will be
+	 * processed in the transfer done callback.
+	 */
+	/* TODO, use global buffer instead of runtime allocations */
+	nbuf = qdf_nbuf_alloc(NULL, len_head_room(len), HEAD_ROOM, 4, 0);
+
+	if (!nbuf) {
+		HIF_ERROR("%s: Unable to alloc netbuf %u bytes", __func__, len);
+		return;
+	}
+
+	hif_read_write(dev, (unsigned long)ch_handle, nbuf->data, len,
+		       HIF_RD_ASYNC_BLOCK_FIX, nbuf);
+}
+
+/**
+ * dl_xfer_cb() - Call from lower layer after transfer is completed
+ * @ch_handle: The sdio al channel handle
+ * @result: The xfer result
+ * @ctx: Context passed in the transfer queuing
+ *
+ * Return: None
+ */
+void dl_xfer_cb(struct sdio_al_channel_handle *ch_handle,
+		struct sdio_al_xfer_result *result,
+		void *ctx)
+{
+	unsigned char *buf;
+	qdf_nbuf_t nbuf;
+	uint32_t len, nbuflen, payload_len = 0;
+	uint8_t *nbufdata;
+	struct hif_sdio_dev *dev;
+	struct hif_sdio_device *device;
+	struct bus_request *bus_req = (struct bus_request *)ctx;
+	bool last_htc_packet = false;
+	QDF_STATUS (*rx_completion)(void *, qdf_nbuf_t, uint8_t);
+
+	if (!ctx)
+		HIF_ERROR("%s: Net buf context NULL!!!", __func__);
+
+	if (!ctx || !ch_handle || !result) {
+		HIF_ERROR("%s: Invalid args", __func__);
+		qdf_assert_always(0);
+		return;
+	}
+
+	dev = (struct hif_sdio_dev *)ch_handle->priv;
+	if (result->xfer_status) {
+		HIF_ERROR("%s: ASYNC Rx failed %d", __func__,
+			  result->xfer_status);
+		/* TODO - Free nbuf if hif_sdio_get_nbuf is used, when bundling
+		 * is enabled
+		 */
+		hif_free_bus_request(dev, (struct bus_request *)ctx);
+		return;
+	}
+
+	device = (struct hif_sdio_device *)dev->htc_context;
+	rx_completion = device->hif_callbacks.rxCompletionHandler;
+
+	buf = (unsigned char *)result->buf_addr;
+	len = (unsigned int)result->xfer_len;
+
+	/* ADMA-TODO - Discard the padding data
+	 * Its still not decided that the padding is informed
+	 * via the hdr->flags or a padding magic inline in the
+	 * buffer. So, lets see.
+	 */
+	while (len > 0 && len >= sizeof(HTC_FRAME_HDR)) {
+		if (last_htc_packet) {
+			HIF_ERROR("ERRR last htc_packet processed already\n");
+			break;
+		}
+		if (HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID) >=
+		    ENDPOINT_MAX) {
+			HIF_ERROR("%s: invalid endpoint id: %u", __func__,
+				  HTC_GET_FIELD(buf, HTC_FRAME_HDR,
+						ENDPOINTID));
+			hif_free_bus_request(dev, (struct bus_request *)ctx);
+			return;
+		}
+		/* last_htc_packet is currently used to test non bundling case
+		 * on Rumi Emulation platform.
+		 * TODO - Remove last_htc_packet logic when bundling is
+		 * enabled and use is_pad_block for bundling
+		 */
+		last_htc_packet = 1;
+		/* TODO - get net buf using hif_sdio_get_nbuf, when bundling is
+		 * enabled
+		 */
+		nbuf = (qdf_nbuf_t)bus_req->context;
+		if (!nbuf) {
+			HIF_ERROR("%s: failed to alloc rx buffer", __func__);
+			break;
+		}
+		nbufdata = qdf_nbuf_data(nbuf);
+		nbuflen = qdf_nbuf_len(nbuf);
+
+		/* Copy the HTC frame to the alloc'd packet buffer */
+		payload_len = HTC_GET_FIELD(buf, HTC_FRAME_HDR, PAYLOADLEN);
+		if (!payload_len) {
+			HIF_ERROR("%s:Invalid Payload len %d bytes", __func__,
+				  payload_len);
+			break;
+		}
+
+		/* TODO - Check if payload fits in netbuf data */
+		if (0) { //nbuflen < payload_len) {
+			HIF_ERROR("%s: nbuf %d < payload %d bytes", __func__,
+				  nbuflen, payload_len);
+			break;
+		}
+
+		qdf_mem_copy(nbufdata, buf,
+			     payload_len + HTC_HEADER_LEN);
+
+		qdf_nbuf_set_pktlen(nbuf, payload_len + HTC_HDR_LENGTH);
+		rx_completion(device->hif_callbacks.Context,
+			      nbuf,
+			      0); /* don't care, not used */
+
+		if (len && last_htc_packet) {
+			unsigned int pad;
+
+			pad = DEV_CALC_RECV_PADDED_LEN(device, payload_len +
+						       HTC_HEADER_LEN);
+			/* Decrement the length to be processed yet */
+			len -= pad;
+			/* Move the data pointer */
+			buf += pad;
+		} else {
+			len -= payload_len + HTC_HDR_LENGTH;
+			buf += payload_len + HTC_HDR_LENGTH;
+		}
+	}
+	hif_free_bus_request(dev, (struct bus_request *)ctx);
+}
diff --git a/hif/src/sdio/transfer/adma.h b/hif/src/sdio/transfer/adma.h
new file mode 100644
index 0000000..f69faf5
--- /dev/null
+++ b/hif/src/sdio/transfer/adma.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _ADMA_H_
+#define _ADMA_H_
+
+#include "hif_sdio_dev.h"
+#include "htc_packet.h"
+#include "htc_api.h"
+#include "hif_internal.h"
+
+/* This should align with the underlying transport layer */
+#define HIF_DEFAULT_IO_BLOCK_SIZE    512
+#define HIF_BLOCK_SIZE               HIF_DEFAULT_IO_BLOCK_SIZE
+#define HIF_DUMMY_SPACE_MASK         0x0FFFFFFF
+
+#define HIF_SDIO_MAX_AL_CHANNELS     2
+
+struct devRegisters {
+	uint32_t dummy;
+};
+
+#include "transfer.h"
+#define DEV_REGISTERS_SIZE           sizeof(struct devRegisters)
+
+uint8_t hif_dev_map_adma_chan_to_pipe(struct hif_sdio_device *pdev,
+				      uint8_t chan, bool upload);
+
+struct sdio_al_channel_handle *hif_dev_map_pipe_to_adma_chan
+(
+struct hif_sdio_device *pdev,
+uint8_t pipeid
+);
+
+void dl_xfer_cb(struct sdio_al_channel_handle *ch_handle,
+		struct sdio_al_xfer_result *result,
+		void *ctx);
+void ul_xfer_cb(struct sdio_al_channel_handle *ch_handle,
+		struct sdio_al_xfer_result *result,
+		void *ctx);
+
+void dl_data_avail_cb(struct sdio_al_channel_handle *ch_handle,
+		      unsigned int len);
+
+void hif_sdio_rx_q_alloc(void *ctx);
+qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev);
+#endif
diff --git a/hif/src/sdio/transfer/mailbox.c b/hif/src/sdio/transfer/mailbox.c
index 84a0a69..30c8b27 100644
--- a/hif/src/sdio/transfer/mailbox.c
+++ b/hif/src/sdio/transfer/mailbox.c
@@ -1,7 +1,6 @@
 /*
  * 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
  * above copyright notice and this permission notice appear in all
@@ -19,6 +18,7 @@
 
 #ifdef CONFIG_SDIO_TRANSFER_MAILBOX
 #define ATH_MODULE_NAME hif
+#include <linux/kthread.h>
 #include <qdf_types.h>
 #include <qdf_status.h>
 #include <qdf_timer.h>
@@ -44,6 +44,24 @@
 #include "regtable.h"
 #include "transfer.h"
 
+/* by default setup a bounce buffer for the data packets,
+ * if the underlying host controller driver
+ * does not use DMA you may be able to skip this step
+ * and save the memory allocation and transfer time
+ */
+#define HIF_USE_DMA_BOUNCE_BUFFER 1
+#if HIF_USE_DMA_BOUNCE_BUFFER
+/* macro to check if DMA buffer is WORD-aligned and DMA-able.
+ * Most host controllers assume the
+ * buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack).
+ * virt_addr_valid check fails on stack memory.
+ */
+#define BUFFER_NEEDS_BOUNCE(buffer)  (((unsigned long)(buffer) & 0x3) || \
+					!virt_addr_valid((buffer)))
+#else
+#define BUFFER_NEEDS_BOUNCE(buffer)   (false)
+#endif
+
 #ifdef SDIO_3_0
 /**
  * set_extended_mbox_size() - set extended MBOX size
@@ -170,6 +188,40 @@
 	}
 }
 
+/** hif_dev_set_mailbox_swap() - Set the mailbox swap from firmware
+ * @pdev : The HIF layer object
+ *
+ * Return: none
+ */
+void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev)
+{
+	struct hif_sdio_device *hif_device = hif_dev_from_hif(pdev);
+
+	HIF_ENTER();
+
+	hif_device->swap_mailbox = true;
+
+	HIF_EXIT();
+}
+
+/** hif_dev_get_mailbox_swap() - Get the mailbox swap setting
+ * @pdev : The HIF layer object
+ *
+ * Return: true or false
+ */
+bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev)
+{
+	struct hif_sdio_device *hif_device;
+
+	HIF_ENTER();
+
+	hif_device = hif_dev_from_hif(pdev);
+
+	HIF_EXIT();
+
+	return hif_device->swap_mailbox;
+}
+
 /**
  * hif_dev_get_fifo_address() - get the fifo addresses for dma
  * @pdev:  SDIO HIF object
@@ -177,22 +229,24 @@
  *
  * Return : 0 for success, non-zero for error
  */
-QDF_STATUS hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
-				    struct hif_device_mbox_info *config,
-				    uint32_t config_len)
+int hif_dev_get_fifo_address(struct hif_sdio_dev *pdev,
+			     void *config,
+			     uint32_t config_len)
 {
 	uint32_t count;
+	struct hif_device_mbox_info *cfg =
+				(struct hif_device_mbox_info *)config;
 
 	for (count = 0; count < 4; count++)
-		config->mbox_addresses[count] = HIF_MBOX_START_ADDR(count);
+		cfg->mbox_addresses[count] = HIF_MBOX_START_ADDR(count);
 
 	if (config_len >= sizeof(struct hif_device_mbox_info)) {
 		set_extended_mbox_window_info((uint16_t)pdev->func->device,
-					      config);
-		return QDF_STATUS_SUCCESS;
+					      cfg);
+		return 0;
 	}
 
-	return QDF_STATUS_E_INVAL;
+	return -EINVAL;
 }
 
 /**
@@ -488,7 +542,7 @@
  * Return 0 for success and non-zero for failure to map
  */
 int hif_get_send_address(struct hif_sdio_device *pdev,
-			 uint8_t pipe, uint32_t *addr)
+			 uint8_t pipe, unsigned long *addr)
 {
 	uint8_t mbox_index = INVALID_MAILBOX_NUMBER;
 
@@ -586,9 +640,9 @@
 	}
 
 	/* mailbox index is saved in Endpoint member */
-	HIF_INFO("%s : hdr:0x%x, len:%d, padded length: %d Mbox:0x%x",
-		 __func__, packet->PktInfo.AsRx.ExpectedHdr, recv_length,
-		 padded_length, mbox_index);
+	HIF_INFO_HI("%s : hdr:0x%x, len:%d, padded length: %d Mbox:0x%x",
+		    __func__, packet->PktInfo.AsRx.ExpectedHdr, recv_length,
+		    padded_length, mbox_index);
 
 	status = hif_read_write(pdev->HIFDevice,
 				pdev->MailBoxInfo.mbox_addresses[mbox_index],
@@ -604,11 +658,11 @@
 		if (status == QDF_STATUS_SUCCESS) {
 			HTC_FRAME_HDR *hdr = (HTC_FRAME_HDR *) packet->pBuffer;
 
-			HIF_INFO("%s: EP:%d,Len:%d,Flag:%d,CB:0x%02X,0x%02X\n",
-				 __func__,
-				 hdr->EndpointID, hdr->PayloadLen,
-				 hdr->Flags, hdr->ControlBytes0,
-				 hdr->ControlBytes1);
+			HIF_INFO_HI("%s:EP:%d,Len:%d,Flg:%d,CB:0x%02X,0x%02X\n",
+				    __func__,
+				    hdr->EndpointID, hdr->PayloadLen,
+				    hdr->Flags, hdr->ControlBytes0,
+				    hdr->ControlBytes1);
 		}
 	}
 
@@ -745,7 +799,7 @@
 	HTC_PACKET_QUEUE recv_q, sync_comp_q;
 	QDF_STATUS (*rxCompletion)(void *, qdf_nbuf_t,	uint8_t);
 
-	HIF_INFO("%s: NumLookAheads: %d\n", __func__, num_look_aheads);
+	HIF_INFO_HI("%s: NumLookAheads: %d\n", __func__, num_look_aheads);
 
 	if (num_pkts_fetched)
 		*num_pkts_fetched = 0;
@@ -1321,33 +1375,610 @@
 	return status;
 }
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) && \
-		 !defined(WITH_BACKPORTS)
+#define DEV_CHECK_RECV_YIELD(pdev) \
+	((pdev)->CurrentDSRRecvCount >= \
+	 (pdev)->HifIRQYieldParams.recv_packet_yield_count)
 /**
- * hif_sdio_set_drvdata() - set wlan driver data into upper layer private
- * @func: pointer to sdio function
- * @hifdevice: pointer to hif device
+ * hif_dev_dsr_handler() - Synchronous interrupt handler
  *
- * Return: non zero for success.
+ * @context: hif send context
+ *
+ * Return: 0 for success and non-zero for failure
  */
-int hif_sdio_set_drvdata(struct sdio_func *func,
-			 struct hif_sdio_dev *hifdevice)
+QDF_STATUS hif_dev_dsr_handler(void *context)
 {
-	return sdio_set_drvdata(func, hifdevice);
+	struct hif_sdio_device *pdev = (struct hif_sdio_device *)context;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	bool done = false;
+	bool async_proc = false;
+
+	/* reset the recv counter that tracks when we need
+	 * to yield from the DSR
+	 */
+	pdev->CurrentDSRRecvCount = 0;
+	/* reset counter used to flag a re-scan of IRQ
+	 * status registers on the target
+	 */
+	pdev->RecheckIRQStatusCnt = 0;
+
+	while (!done) {
+		status = hif_dev_process_pending_irqs(pdev, &done, &async_proc);
+		if (QDF_IS_STATUS_ERROR(status))
+			break;
+
+		if (pdev->HifIRQProcessingMode == HIF_DEVICE_IRQ_SYNC_ONLY) {
+			/* the HIF layer does not allow async IRQ processing,
+			 * override the asyncProc flag
+			 */
+			async_proc = false;
+			/* this will cause us to re-enter ProcessPendingIRQ()
+			 * and re-read interrupt status registers.
+			 * This has a nice side effect of blocking us until all
+			 * async read requests are completed. This behavior is
+			 * required as we  do not allow ASYNC processing
+			 * in interrupt handlers (like Windows CE)
+			 */
+
+			if (pdev->DSRCanYield && DEV_CHECK_RECV_YIELD(pdev))
+				/* ProcessPendingIRQs() pulled enough recv
+				 * messages to satisfy the yield count, stop
+				 * checking for more messages and return
+				 */
+				break;
+		}
+
+		if (async_proc) {
+			/* the function does some async I/O for performance,
+			 * we need to exit the ISR immediately, the check below
+			 * will prevent the interrupt from being
+			 * Ack'd while we handle it asynchronously
+			 */
+			break;
+		}
+	}
+
+	if (QDF_IS_STATUS_SUCCESS(status) && !async_proc) {
+		/* Ack the interrupt only if :
+		 *  1. we did not get any errors in processing interrupts
+		 *  2. there are no outstanding async processing requests
+		 */
+		if (pdev->DSRCanYield) {
+			/* if the DSR can yield do not ACK the interrupt, there
+			 * could be more pending messages. The HIF layer
+			 * must ACK the interrupt on behalf of HTC
+			 */
+			HIF_INFO("%s:  Yield (RX count: %d)",
+				 __func__, pdev->CurrentDSRRecvCount);
+		} else {
+			hif_ack_interrupt(pdev->HIFDevice);
+		}
+	}
+
+	return status;
 }
-#else
-int hif_sdio_set_drvdata(struct sdio_func *func,
-			 struct hif_sdio_dev *hifdevice)
+
+/**
+ * hif_read_write() - queue a read/write request
+ * @device: pointer to hif device structure
+ * @address: address to read
+ * @buffer: buffer to hold read/write data
+ * @length: length to read/write
+ * @request: read/write/sync/async request
+ * @context: pointer to hold calling context
+ *
+ * Return: 0 on success, error number otherwise.
+ */
+QDF_STATUS
+hif_read_write(struct hif_sdio_dev *device,
+	       unsigned long address,
+	       char *buffer, uint32_t length,
+	       uint32_t request, void *context)
 {
-	sdio_set_drvdata(func, hifdevice);
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct bus_request *busrequest;
+
+	AR_DEBUG_ASSERT(device);
+	AR_DEBUG_ASSERT(device->func);
+	HIF_TRACE("%s: device 0x%pK addr 0x%lX buffer 0x%pK",
+		  __func__, device, address, buffer);
+	HIF_TRACE("%s: len %d req 0x%X context 0x%pK",
+		  __func__, length, request, context);
+
+	/*sdio r/w action is not needed when suspend, so just return */
+	if ((device->is_suspend) &&
+	    (device->power_config == HIF_DEVICE_POWER_CUT)) {
+		AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("skip io when suspending\n"));
+		return QDF_STATUS_SUCCESS;
+	}
+	do {
+		if ((request & HIF_ASYNCHRONOUS) ||
+		    (request & HIF_SYNCHRONOUS)) {
+			/* serialize all requests through the async thread */
+			AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
+					("%s: Execution mode: %s\n", __func__,
+					 (request & HIF_ASYNCHRONOUS) ? "Async"
+					 : "Synch"));
+			busrequest = hif_allocate_bus_request(device);
+			if (!busrequest) {
+				HIF_ERROR("%s:bus requests unavail", __func__);
+				HIF_ERROR("%s, addr:0x%lX, len:%d",
+					  request & HIF_SDIO_READ ? "READ" :
+					  "WRITE", address, length);
+				return QDF_STATUS_E_FAILURE;
+			}
+			busrequest->address = address;
+			busrequest->buffer = buffer;
+			busrequest->length = length;
+			busrequest->request = request;
+			busrequest->context = context;
+
+			add_to_async_list(device, busrequest);
+
+			if (request & HIF_SYNCHRONOUS) {
+				AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
+						("%s: queued sync req: 0x%lX\n",
+						 __func__,
+						 (unsigned long)busrequest));
+
+				/* wait for completion */
+				up(&device->sem_async);
+				if (down_interruptible(&busrequest->sem_req) ==
+				    0) {
+					QDF_STATUS status = busrequest->status;
+
+					HIF_TRACE("%s: sync freeing 0x%lX:0x%X",
+						  __func__,
+						  (unsigned long)busrequest,
+						  busrequest->status);
+					HIF_TRACE("%s: freeing req: 0x%X",
+						  __func__,
+						  (unsigned int)request);
+					hif_free_bus_request(device,
+							     busrequest);
+					return status;
+				} else {
+					/* interrupted, exit */
+					return QDF_STATUS_E_FAILURE;
+				}
+			} else {
+				HIF_TRACE("%s: queued async req: 0x%lX",
+					  __func__, (unsigned long)busrequest);
+				up(&device->sem_async);
+				return QDF_STATUS_E_PENDING;
+			}
+		} else {
+			HIF_ERROR("%s: Invalid execution mode: 0x%08x",
+				  __func__, (unsigned int)request);
+			status = QDF_STATUS_E_INVAL;
+			break;
+		}
+	} while (0);
+
+	return status;
+}
+
+/**
+ * hif_sdio_func_enable() - Handle device enabling as per device
+ * @device: HIF device object
+ * @func: function pointer
+ *
+ * Return success or failure
+ */
+static int hif_sdio_func_enable(struct hif_softc *ol_sc,
+				struct sdio_func *func)
+{
+	struct hif_sdio_dev *device = get_hif_device(ol_sc, func);
+
+	if (device->is_disabled) {
+		int ret = 0;
+
+		sdio_claim_host(func);
+
+		ret = hif_sdio_quirk_async_intr(ol_sc, func);
+		if (ret) {
+			HIF_ERROR("%s: Error setting async intr:%d",
+				  __func__, ret);
+			sdio_release_host(func);
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		func->enable_timeout = 100;
+		ret = sdio_enable_func(func);
+		if (ret) {
+			HIF_ERROR("%s: Unable to enable function: %d",
+				  __func__, ret);
+			sdio_release_host(func);
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		ret = sdio_set_block_size(func, HIF_BLOCK_SIZE);
+		if (ret) {
+			HIF_ERROR("%s: Unable to set block size 0x%X : %d\n",
+				  __func__, HIF_BLOCK_SIZE, ret);
+			sdio_release_host(func);
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		ret = hif_sdio_quirk_mod_strength(ol_sc, func);
+		if (ret) {
+			HIF_ERROR("%s: Error setting mod strength : %d\n",
+				  __func__, ret);
+			sdio_release_host(func);
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		sdio_release_host(func);
+	}
+
 	return 0;
 }
-#endif /* LINUX VERSION */
 
-struct hif_sdio_dev *get_hif_device(struct sdio_func *func)
+/**
+ * __hif_read_write() - sdio read/write wrapper
+ * @device: pointer to hif device structure
+ * @address: address to read
+ * @buffer: buffer to hold read/write data
+ * @length: length to read/write
+ * @request: read/write/sync/async request
+ * @context: pointer to hold calling context
+ *
+ * Return: 0 on success, error number otherwise.
+ */
+static QDF_STATUS
+__hif_read_write(struct hif_sdio_dev *device,
+		 uint32_t address, char *buffer,
+		 uint32_t length, uint32_t request, void *context)
 {
-	qdf_assert(func);
+	uint8_t opcode;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	int ret = A_OK;
+	uint8_t *tbuffer;
+	bool bounced = false;
 
-	return (struct hif_sdio_dev *)sdio_get_drvdata(func);
+	if (!device) {
+		HIF_ERROR("%s: device null!", __func__);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!device->func) {
+		HIF_ERROR("%s: func null!", __func__);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	HIF_INFO_HI("%s: addr:0X%06X, len:%08d, %s, %s", __func__,
+		    address, length,
+		    request & HIF_SDIO_READ ? "Read " : "Write",
+		    request & HIF_ASYNCHRONOUS ? "Async" : "Sync ");
+
+	do {
+		if (request & HIF_EXTENDED_IO) {
+			HIF_INFO_HI("%s: Command type: CMD53\n", __func__);
+		} else {
+			HIF_ERROR("%s: Invalid command type: 0x%08x\n",
+				  __func__, request);
+			status = QDF_STATUS_E_INVAL;
+			break;
+		}
+
+		if (request & HIF_BLOCK_BASIS) {
+			/* round to whole block length size */
+			length =
+				(length / HIF_BLOCK_SIZE) *
+				HIF_BLOCK_SIZE;
+			HIF_INFO_HI("%s: Block mode (BlockLen: %d)\n",
+				    __func__, length);
+		} else if (request & HIF_BYTE_BASIS) {
+			HIF_INFO_HI("%s: Byte mode (BlockLen: %d)\n",
+				    __func__, length);
+		} else {
+			HIF_ERROR("%s: Invalid data mode: 0x%08x\n",
+				  __func__, request);
+			status = QDF_STATUS_E_INVAL;
+			break;
+		}
+		if (request & HIF_SDIO_WRITE) {
+			hif_fixup_write_param(device, request,
+					      &length, &address);
+
+			HIF_INFO_HI("addr:%08X, len:0x%08X, dummy:0x%04X\n",
+				    address, length,
+				    (request & HIF_DUMMY_SPACE_MASK) >> 16);
+		}
+
+		if (request & HIF_FIXED_ADDRESS) {
+			opcode = CMD53_FIXED_ADDRESS;
+			HIF_INFO_HI("%s: Addr mode: fixed 0x%X\n",
+				    __func__, address);
+		} else if (request & HIF_INCREMENTAL_ADDRESS) {
+			opcode = CMD53_INCR_ADDRESS;
+			HIF_INFO_HI("%s: Address mode: Incremental 0x%X\n",
+				    __func__, address);
+		} else {
+			HIF_ERROR("%s: Invalid address mode: 0x%08x\n",
+				  __func__, request);
+			status = QDF_STATUS_E_INVAL;
+			break;
+		}
+
+		if (request & HIF_SDIO_WRITE) {
+#if HIF_USE_DMA_BOUNCE_BUFFER
+			if (BUFFER_NEEDS_BOUNCE(buffer)) {
+				AR_DEBUG_ASSERT(device->dma_buffer);
+				tbuffer = device->dma_buffer;
+				/* copy the write data to the dma buffer */
+				AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
+				if (length > HIF_DMA_BUFFER_SIZE) {
+					HIF_ERROR("%s: Invalid write len: %d\n",
+						  __func__, length);
+					status = QDF_STATUS_E_INVAL;
+					break;
+				}
+				memcpy(tbuffer, buffer, length);
+				bounced = true;
+			} else {
+				tbuffer = buffer;
+			}
+#else
+			tbuffer = buffer;
+#endif
+			if (opcode == CMD53_FIXED_ADDRESS  && tbuffer) {
+				ret = sdio_writesb(device->func, address,
+						   tbuffer, length);
+				HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
+					    __func__, ret, address, length,
+					    *(int *)tbuffer);
+			} else if (tbuffer) {
+				ret = sdio_memcpy_toio(device->func, address,
+						       tbuffer, length);
+				HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
+					    __func__, ret, address, length,
+					    *(int *)tbuffer);
+			}
+		} else if (request & HIF_SDIO_READ) {
+#if HIF_USE_DMA_BOUNCE_BUFFER
+			if (BUFFER_NEEDS_BOUNCE(buffer)) {
+				AR_DEBUG_ASSERT(device->dma_buffer);
+				AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
+				if (length > HIF_DMA_BUFFER_SIZE) {
+					HIF_ERROR("%s: Invalid read len: %d\n",
+						  __func__, length);
+					status = QDF_STATUS_E_INVAL;
+					break;
+				}
+				tbuffer = device->dma_buffer;
+				bounced = true;
+			} else {
+				tbuffer = buffer;
+			}
+#else
+			tbuffer = buffer;
+#endif
+			if (opcode == CMD53_FIXED_ADDRESS && tbuffer) {
+				ret = sdio_readsb(device->func, tbuffer,
+						  address, length);
+				HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
+					    __func__, ret, address, length,
+					    *(int *)tbuffer);
+			} else if (tbuffer) {
+				ret = sdio_memcpy_fromio(device->func,
+							 tbuffer, address,
+							 length);
+				HIF_INFO_HI("%s:r=%d addr:0x%X, len:%d, 0x%X\n",
+					    __func__, ret, address, length,
+					    *(int *)tbuffer);
+			}
+#if HIF_USE_DMA_BOUNCE_BUFFER
+			if (bounced && tbuffer)
+				memcpy(buffer, tbuffer, length);
+#endif
+		} else {
+			HIF_ERROR("%s: Invalid dir: 0x%08x", __func__, request);
+			status = QDF_STATUS_E_INVAL;
+			return status;
+		}
+
+		if (ret) {
+			HIF_ERROR("%s: SDIO bus operation failed!", __func__);
+			HIF_ERROR("%s: MMC stack returned : %d", __func__, ret);
+			HIF_ERROR("%s: addr:0X%06X, len:%08d, %s, %s",
+				  __func__, address, length,
+				  request & HIF_SDIO_READ ? "Read " : "Write",
+				  request & HIF_ASYNCHRONOUS ?
+				  "Async" : "Sync");
+			status = QDF_STATUS_E_FAILURE;
+		}
+	} while (false);
+
+	return status;
+}
+
+/**
+ * async_task() - thread function to serialize all bus requests
+ * @param: pointer to hif device
+ *
+ * thread function to serialize all requests, both sync and async
+ * Return: 0 on success, error number otherwise.
+ */
+static int async_task(void *param)
+{
+	struct hif_sdio_dev *device;
+	struct bus_request *request;
+	QDF_STATUS status;
+	bool claimed = false;
+
+	device = (struct hif_sdio_dev *)param;
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (!device->async_shutdown) {
+		/* wait for work */
+		if (down_interruptible(&device->sem_async) != 0) {
+			/* interrupted, exit */
+			AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
+					("%s: async task interrupted\n",
+					 __func__));
+			break;
+		}
+		if (device->async_shutdown) {
+			AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
+					("%s: async task stopping\n",
+					 __func__));
+			break;
+		}
+		/* we want to hold the host over multiple cmds
+		 * if possible, but holding the host blocks
+		 * card interrupts
+		 */
+		qdf_spin_lock_irqsave(&device->asynclock);
+		/* pull the request to work on */
+		while (device->asyncreq) {
+			request = device->asyncreq;
+			if (request->inusenext)
+				device->asyncreq = request->inusenext;
+			else
+				device->asyncreq = NULL;
+			qdf_spin_unlock_irqrestore(&device->asynclock);
+			HIF_TRACE("%s: processing req: 0x%lX",
+				  __func__, (unsigned long)request);
+
+			if (!claimed) {
+				sdio_claim_host(device->func);
+				claimed = true;
+			}
+			if (request->scatter_req) {
+				A_ASSERT(device->scatter_enabled);
+				/* pass the request to scatter routine which
+				 * executes it synchronously, note, no need
+				 * to free the request since scatter requests
+				 * are maintained on a separate list
+				 */
+				status = do_hif_read_write_scatter(device,
+								   request);
+			} else {
+				/* call hif_read_write in sync mode */
+				status =
+					__hif_read_write(device,
+							 request->address,
+							 request->buffer,
+							 request->length,
+							 request->
+							 request &
+							 ~HIF_SYNCHRONOUS,
+							 NULL);
+				if (request->request & HIF_ASYNCHRONOUS) {
+					void *context = request->context;
+
+					HIF_TRACE("%s: freeing req: 0x%lX",
+						  __func__,
+						  (unsigned long)request);
+					hif_free_bus_request(device, request);
+
+					HIF_TRACE("%s: completion req 0x%lX",
+						  __func__,
+						  (unsigned long)request);
+					device->htc_callbacks.
+					rw_compl_handler(context, status);
+				} else {
+					HIF_TRACE("%s: upping req: 0x%lX",
+						  __func__,
+						  (unsigned long)request);
+					request->status = status;
+					up(&request->sem_req);
+				}
+			}
+			qdf_spin_lock_irqsave(&device->asynclock);
+		}
+		qdf_spin_unlock_irqrestore(&device->asynclock);
+		if (claimed) {
+			sdio_release_host(device->func);
+			claimed = false;
+		}
+	}
+
+	complete_and_exit(&device->async_completion, 0);
+
+	return 0;
+}
+
+/**
+ * hif_disable_func() - Disable SDIO function
+ *
+ * @device: HIF device pointer
+ * @func: SDIO function pointer
+ * @reset: If this is called from resume or probe
+ *
+ * Return: 0 in case of success, else error value
+ */
+QDF_STATUS hif_disable_func(struct hif_sdio_dev *device,
+			    struct sdio_func *func,
+			    bool reset)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	HIF_ENTER();
+	if (!IS_ERR(device->async_task)) {
+		init_completion(&device->async_completion);
+		device->async_shutdown = 1;
+		up(&device->sem_async);
+		wait_for_completion(&device->async_completion);
+		device->async_task = NULL;
+		sema_init(&device->sem_async, 0);
+	}
+
+	status = hif_sdio_func_disable(device, func, reset);
+	if (status == QDF_STATUS_SUCCESS)
+		device->is_disabled = true;
+
+	cleanup_hif_scatter_resources(device);
+
+	HIF_EXIT();
+
+	return status;
+}
+
+/**
+ * hif_enable_func() - Enable SDIO function
+ *
+ * @ol_sc: HIF object pointer
+ * @device: HIF device pointer
+ * @sdio_func: SDIO function pointer
+ * @resume: If this is called from resume or probe
+ *
+ * Return: 0 in case of success, else error value
+ */
+QDF_STATUS hif_enable_func(struct hif_softc *ol_sc, struct hif_sdio_dev *device,
+			   struct sdio_func *func, bool resume)
+{
+	int ret = QDF_STATUS_SUCCESS;
+
+	HIF_ENTER();
+
+	if (!device) {
+		HIF_ERROR("%s: HIF device is NULL", __func__);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (hif_sdio_func_enable(ol_sc, func))
+		return QDF_STATUS_E_FAILURE;
+
+	/* create async I/O thread */
+	if (!device->async_task && device->is_disabled) {
+		device->async_shutdown = 0;
+		device->async_task = kthread_create(async_task,
+						    (void *)device,
+						    "AR6K Async");
+		if (IS_ERR(device->async_task)) {
+			HIF_ERROR("%s: Error creating async task",
+				  __func__);
+			return QDF_STATUS_E_FAILURE;
+		}
+		device->is_disabled = false;
+		wake_up_process(device->async_task);
+	}
+
+	if (!resume)
+		ret = hif_sdio_probe(ol_sc, func, device);
+
+	HIF_EXIT();
+
+	return ret;
 }
 #endif /* CONFIG_SDIO_TRANSFER_MAILBOX */
diff --git a/hif/src/sdio/transfer/mailbox.h b/hif/src/sdio/transfer/mailbox.h
index 9123d87..3e59132 100644
--- a/hif/src/sdio/transfer/mailbox.h
+++ b/hif/src/sdio/transfer/mailbox.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016-2019 The Linux Foundation. All rights reserved.
  *
  *
  *
@@ -146,11 +146,6 @@
  */
 #define HIF_DUMMY_SPACE_MASK                   0xFFFF0000
 
-/*
- * data written into the dummy space will not put into the final mbox FIFO
- */
-#define HIF_DUMMY_SPACE_MASK                   0xFFFF0000
-
 PREPACK struct MBOX_IRQ_PROC_REGISTERS {
 	uint8_t host_int_status;
 	uint8_t cpu_int_status;
@@ -190,4 +185,9 @@
 #define DEV_REGISTERS_SIZE	(sizeof(struct MBOX_IRQ_PROC_REGISTERS) + \
 				 sizeof(struct MBOX_IRQ_ENABLE_REGISTERS) + \
 				 sizeof(struct MBOX_COUNTER_REGISTERS))
+
+void hif_dev_dump_registers(struct hif_sdio_device *pdev,
+			    struct MBOX_IRQ_PROC_REGISTERS *irq_proc,
+			    struct MBOX_IRQ_ENABLE_REGISTERS *irq_en,
+			    struct MBOX_COUNTER_REGISTERS *mbox_regs);
 #endif /* _MAILBOX_H_ */
diff --git a/hif/src/sdio/transfer/transfer.c b/hif/src/sdio/transfer/transfer.c
index 07ebf52..a7837c8 100644
--- a/hif/src/sdio/transfer/transfer.c
+++ b/hif/src/sdio/transfer/transfer.c
@@ -91,7 +91,8 @@
 	unsigned char *pData;
 	struct hif_sendContext *sctx;
 	uint32_t request = hif_get_send_buffer_flags(pdev);
-	uint32_t padded_length, addr = 0;
+	uint32_t padded_length;
+	unsigned long addr = 0;
 	int frag_count = 0, i, count, head_len;
 
 	if (hif_get_send_address(pdev, pipe, &addr)) {
@@ -381,7 +382,7 @@
 	HTC_RECORD_HDR *record;
 	HTC_LOOKAHEAD_REPORT *look_ahead;
 
-	HIF_INFO("%s: length:%d", __func__, length);
+	HIF_INFO_HI("%s: length:%d", __func__, length);
 
 	orig_buffer = buffer;
 	orig_length = length;
@@ -515,7 +516,7 @@
 		debug_dump_bytes(orig_buffer, orig_length,
 				 "BAD Recv Trailer");
 
-	HIF_INFO("%s: status = %d", __func__, status);
+	HIF_INFO_HI("%s: status = %d", __func__, status);
 
 	return status;
 }
diff --git a/hif/src/sdio/transfer/transfer.h b/hif/src/sdio/transfer/transfer.h
index 4a72838..73d6b53 100644
--- a/hif/src/sdio/transfer/transfer.h
+++ b/hif/src/sdio/transfer/transfer.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.
  *
  *
  *
@@ -65,13 +65,8 @@
 	unsigned int head_data_len;
 };
 
-void hif_dev_dump_registers(struct hif_sdio_device *pdev,
-			    struct MBOX_IRQ_PROC_REGISTERS *irq_proc,
-			    struct MBOX_IRQ_ENABLE_REGISTERS *irq_en,
-			    struct MBOX_COUNTER_REGISTERS *mbox_regs);
-
 int hif_get_send_address(struct hif_sdio_device *pdev,
-			 uint8_t pipe, uint32_t *addr);
+			 uint8_t pipe, unsigned long *addr);
 
 QDF_STATUS hif_dev_alloc_and_prepare_rx_packets(struct hif_sdio_device *pdev,
 						uint32_t look_aheads[],
@@ -104,7 +99,11 @@
 	return 0;
 }
 #elif defined(CONFIG_SDIO_TRANSFER_ADMA)
-#error "Error - Not implemented yet"
+static inline uint32_t hif_get_send_buffer_flags(struct hif_sdio_device *pdev)
+{
+	/* ADAM-TODO */
+	return (uint32_t)HIF_WR_ASYNC_BLOCK_FIX;
+}
 #endif
 
 #endif /* __TRANSFER_H__ */
diff --git a/umac/cp_stats/core/src/wlan_cp_stats_defs.h b/umac/cp_stats/core/src/wlan_cp_stats_defs.h
index a71c392..762cdfe 100644
--- a/umac/cp_stats/core/src/wlan_cp_stats_defs.h
+++ b/umac/cp_stats/core/src/wlan_cp_stats_defs.h
@@ -47,6 +47,8 @@
  * @psoc_cp_stats_lock: lock to protect object
  * @cmn_stats: stats common for AP and STA devices
  * @obj_stats: stats specific to AP or STA devices
+ * @legacy_stats_cb: callback to update the stats received from FW through
+ * asynchronous events.
  */
 struct psoc_cp_stats {
 	struct wlan_objmgr_psoc *psoc_obj;
@@ -54,6 +56,7 @@
 	qdf_spinlock_t psoc_cp_stats_lock;
 	struct psoc_cmn_cp_stats *cmn_stats;
 	psoc_ext_cp_stats_t *obj_stats;
+	void (*legacy_stats_cb)(void *stats);
 };
 
 /**
diff --git a/umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h b/umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h
index 5b14851..200eef9 100644
--- a/umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h
+++ b/umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h
@@ -205,6 +205,17 @@
 QDF_STATUS ucfg_mc_cp_stats_set_rate_flags(struct wlan_objmgr_vdev *vdev,
 					   enum tx_rate_info flags);
 
+/**
+ * ucfg_mc_cp_stats_register_lost_link_info_cb() - API to register lost link
+ * info callback
+ * @psoc: pointer to psoc object
+ * @lost_link_cp_stats_info_cb: Lost link info callback to be registered
+ *
+ */
+void ucfg_mc_cp_stats_register_lost_link_info_cb(
+		struct wlan_objmgr_psoc *psoc,
+		void (*lost_link_cp_stats_info_cb)(void *stats_ev));
+
 #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD
 /**
  * ucfg_mc_cp_stats_register_pmo_handler() - API to register pmo handler
diff --git a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c
index a77494c..e517fb8 100644
--- a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c
+++ b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c
@@ -848,6 +848,16 @@
 	}
 }
 
+static void tgt_mc_cp_send_lost_link_stats(struct wlan_objmgr_psoc *psoc,
+					   struct stats_event *ev)
+{
+	struct psoc_cp_stats *psoc_cp_stats_priv;
+
+	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
+	if (psoc_cp_stats_priv && psoc_cp_stats_priv->legacy_stats_cb)
+		psoc_cp_stats_priv->legacy_stats_cb(ev);
+}
+
 QDF_STATUS tgt_mc_cp_stats_process_stats_event(struct wlan_objmgr_psoc *psoc,
 					       struct stats_event *ev)
 {
@@ -862,6 +872,7 @@
 
 	tgt_mc_cp_stats_extract_cca_stats(psoc, ev);
 
+	tgt_mc_cp_send_lost_link_stats(psoc, ev);
 	return QDF_STATUS_SUCCESS;
 }
 
diff --git a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c
index 97779ef..ca85ca1 100644
--- a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c
+++ b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c
@@ -640,6 +640,21 @@
 	return QDF_STATUS_SUCCESS;
 }
 
+void ucfg_mc_cp_stats_register_lost_link_info_cb(
+			struct wlan_objmgr_psoc *psoc,
+			void (*lost_link_cp_stats_info_cb)(void *stats_ev))
+{
+	struct psoc_cp_stats *psoc_cp_stats_priv;
+
+	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
+	if (!psoc_cp_stats_priv) {
+		cp_stats_err("psoc cp stats object is null");
+		return;
+	}
+
+	psoc_cp_stats_priv->legacy_stats_cb = lost_link_cp_stats_info_cb;
+}
+
 #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD
 static QDF_STATUS
 ucfg_mc_cp_stats_suspend_req_handler(struct wlan_objmgr_psoc *psoc)
diff --git a/umac/dfs/core/src/dfs.h b/umac/dfs/core/src/dfs.h
index 99ac566..4dc9c14 100644
--- a/umac/dfs/core/src/dfs.h
+++ b/umac/dfs/core/src/dfs.h
@@ -1031,8 +1031,13 @@
  * @dfs_nol_ie_bitmap:               The bitmap of radar affected subchannels
  *                                   in the current channel list
  *                                   to be sent in NOL IE with RCSA.
- * @dfs_is_rcsa_ie_sent              To send or to not send RCSA IE.
- * @dfs_is_nol_ie_sent               To send or to not send NOL IE.
+ * @dfs_is_rcsa_ie_sent:             To send or to not send RCSA IE.
+ * @dfs_is_nol_ie_sent:              To send or to not send NOL IE.
+ * @dfs_allow_hw_pulses:             Allow/Block HW pulses. When synthetic
+ *                                   pulses are injected, the HW pulses should
+ *                                   be blocked and this variable should be
+ *                                   false so that HW pulses and synthetic
+ *                                   pulses do not get mixed up.
  */
 struct wlan_dfs {
 	uint32_t       dfs_debug_mask;
@@ -1174,6 +1179,9 @@
 	bool           dfs_is_rcsa_ie_sent;
 	bool           dfs_is_nol_ie_sent;
 	bool           dfs_agile_precac_enable;
+#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(WLAN_DFS_SYNTHETIC_RADAR)
+	bool           dfs_allow_hw_pulses;
+#endif
 };
 
 #if defined(QCA_SUPPORT_AGILE_DFS) || defined(ATH_SUPPORT_ZERO_CAC_DFS)
diff --git a/umac/dfs/core/src/dfs_partial_offload_radar.h b/umac/dfs/core/src/dfs_partial_offload_radar.h
index 40b94f6..4fb8f7e 100644
--- a/umac/dfs/core/src/dfs_partial_offload_radar.h
+++ b/umac/dfs/core/src/dfs_partial_offload_radar.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -197,4 +197,56 @@
 {
 }
 #endif
+
+#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(WLAN_DFS_SYNTHETIC_RADAR)
+/**
+ * dfs_allow_hw_pulses() - Set or unset dfs_allow_hw_pulses
+ * which allow or disallow HW pulses.
+ * @dfs: Pointer to DFS pdev object.
+ * @allow_hw_pulses: allow/disallow synthetic pulse detection true/false.
+ *
+ * Return: void
+ */
+void dfs_allow_hw_pulses(struct wlan_dfs *dfs, bool allow_hw_pulses);
+#else
+static inline void dfs_allow_hw_pulses(struct wlan_dfs *dfs,
+				       bool allow_hw_pulses)
+{
+}
+#endif
+
+#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(WLAN_DFS_SYNTHETIC_RADAR)
+/**
+ * dfs_is_hw_pulses_allowed() - Check if HW pulses are allowed or not.
+ * @pdev: Pointer to DFS pdev object.
+ *
+ * Return: bool
+ */
+bool dfs_is_hw_pulses_allowed(struct wlan_dfs *dfs);
+#else
+static inline bool dfs_is_hw_pulses_allowed(struct wlan_dfs *dfs)
+{
+	return true;
+}
+#endif
+
+/**
+ * dfs_inject_synthetic_pulse_sequence() - Inject the synthetic pulse to the
+ * phyerror processing algorithm.
+ * @dfs: Pointer to wlan_dfs structure.
+ * @buf: Pointer to buffer of pulses.
+ *
+ * Return: QDF_STATUS
+ */
+#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(WLAN_DFS_SYNTHETIC_RADAR)
+QDF_STATUS dfs_inject_synthetic_pulse_sequence(struct wlan_dfs *dfs,
+					       unsigned char *buf);
+#else
+static inline
+QDF_STATUS dfs_inject_synthetic_pulse_sequence(struct wlan_dfs *dfs,
+					       unsigned char *buf)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_DFS_PARTIAL_OFFLOAD && WLAN_DFS_SYNTHETIC_RADAR */
 #endif /*  _DFS_PARTIAL_OFFLOAD_RADAR_H_ */
diff --git a/umac/dfs/core/src/misc/dfs.c b/umac/dfs/core/src/misc/dfs.c
index 9420f39..0c2a3a0 100644
--- a/umac/dfs/core/src/misc/dfs.c
+++ b/umac/dfs/core/src/misc/dfs.c
@@ -705,6 +705,20 @@
 		dfs_reset_precac_lists(dfs);
 		dfs_reset_etsi_precac_lists(dfs);
 		break;
+	case DFS_INJECT_SEQUENCE:
+		error = dfs_inject_synthetic_pulse_sequence(dfs, indata);
+		if (error)
+			dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
+				  "Not injected Synthetic pulse");
+		break;
+
+	case DFS_ALLOW_HW_PULSES:
+		if (insize < sizeof(u_int8_t) || !indata) {
+			error = -EINVAL;
+			break;
+		}
+		dfs_allow_hw_pulses(dfs, !!(*(u_int8_t *)indata));
+		break;
 	default:
 		error = -EINVAL;
 	}
diff --git a/umac/dfs/core/src/misc/dfs_filter_init.c b/umac/dfs/core/src/misc/dfs_filter_init.c
index 7a7ba25..01f3b82 100644
--- a/umac/dfs/core/src/misc/dfs_filter_init.c
+++ b/umac/dfs/core/src/misc/dfs_filter_init.c
@@ -218,6 +218,7 @@
 	/*Verify : Passing NULL to qdf_timer_init().*/
 	dfs_main_task_timer_init(dfs);
 
+	dfs_allow_hw_pulses(dfs, true);
 	dfs_host_wait_timer_init(dfs);
 
 	WLAN_DFSQ_LOCK_CREATE(dfs);
diff --git a/umac/dfs/dispatcher/inc/wlan_dfs_ioctl.h b/umac/dfs/dispatcher/inc/wlan_dfs_ioctl.h
index a1f11c2..9cc3344 100644
--- a/umac/dfs/dispatcher/inc/wlan_dfs_ioctl.h
+++ b/umac/dfs/dispatcher/inc/wlan_dfs_ioctl.h
@@ -53,12 +53,15 @@
 #define DFS_SET_DISABLE_RADAR_MARKING 25
 #define DFS_GET_DISABLE_RADAR_MARKING 26
 
+#define DFS_INJECT_SEQUENCE 27
+#define DFS_ALLOW_HW_PULSES 28
+
 /*
  * Spectral IOCTLs use DFS_LAST_IOCTL as the base.
  * This must always be the last IOCTL in DFS and have
  * the highest value.
  */
-#define DFS_LAST_IOCTL 27
+#define DFS_LAST_IOCTL 29
 
 #ifndef DFS_CHAN_MAX
 #define DFS_CHAN_MAX 1023
@@ -271,4 +274,69 @@
 	WLAN_EV_NOL_FINISHED,
 };
 
+#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(WLAN_DFS_SYNTHETIC_RADAR)
+/**
+ * Structure of Pulse to be injected into the DFS Module
+ * ******************************************************
+ * Header
+ * ======
+ * ----------|--------------|
+ * num_pulses| total_len_seq|
+ * ----------|--------------|
+ * Buffer Contents per pulse:
+ * ==========================
+ * ------|----------|-----------|----------|-----------|---------------|--------
+ * r_rssi|r_ext_rssi|r_rs_tstamp|r_fulltsf |fft_datalen|total_len_pulse|FFT
+ *       |          |           |          |           |               |Buffer..
+ * ------|----------|-----------|----------|-----------|---------------|--------
+ */
+
+/**
+ * struct synthetic_pulse - Radar Pulse Structure to be filled on reading the
+ * user file.
+ * @r_rssi:          RSSI of the pulse.
+ * @r_ext_rssi:      Extension Channel RSSI.
+ * @r_rs_tstamp:     Timestamp.
+ * @r_fulltsf:       TSF64.
+ * @fft_datalen:     Total len of FFT.
+ * @total_len_pulse: Total len of the pulse.
+ * @fft_buf:         Pointer to fft data.
+ */
+
+struct synthetic_pulse {
+	uint8_t r_rssi;
+	uint8_t r_ext_rssi;
+	uint32_t r_rs_tstamp;
+	uint64_t r_fulltsf;
+	uint16_t fft_datalen;
+	uint16_t total_len_pulse;
+	unsigned char *fft_buf;
+} qdf_packed;
+
+/**
+ * struct synthetic_seq - Structure to hold an array of pointers to the
+ * pulse structure.
+ * @num_pulses:    Total num of pulses in the sequence.
+ * @total_len_seq: Total len of the sequence.
+ * @pulse:         Array of pointers to synthetic_pulse structure.
+ */
+
+struct synthetic_seq {
+	uint8_t num_pulses;
+	uint32_t total_len_seq;
+	struct synthetic_pulse *pulse[0];
+};
+
+/**
+ * struct seq_store - Structure to hold an array of pointers to the synthetic
+ * sequence structure.
+ * @num_sequence: Total number of "sequence of pulses" in the file.
+ * @seq_arr:      Array of pointers to synthetic_seq structure.
+ */
+
+struct seq_store {
+	uint8_t num_sequence;
+	struct synthetic_seq *seq_arr[0];
+};
+#endif /* WLAN_DFS_PARTIAL_OFFLOAD && WLAN_DFS_SYNTHETIC_RADAR */
 #endif  /* _DFS_IOCTL_H_ */
diff --git a/umac/dfs/dispatcher/inc/wlan_dfs_ucfg_api.h b/umac/dfs/dispatcher/inc/wlan_dfs_ucfg_api.h
index 9c409cc..35f6f7f 100644
--- a/umac/dfs/dispatcher/inc/wlan_dfs_ucfg_api.h
+++ b/umac/dfs/dispatcher/inc/wlan_dfs_ucfg_api.h
@@ -345,6 +345,46 @@
 }
 #endif
 
+#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(WLAN_DFS_SYNTHETIC_RADAR)
+/**
+ * ucfg_dfs_allow_hw_pulses() - Set or unset dfs-allow_hw_pulses
+ * which isolates synthetic radar pulse detection from actual radar detection.
+ * @pdev: Pointer to DFS pdev object.
+ * @allow_hw_pulses: Allow synthetic pulse detection true/false.
+ *
+ * Wrapper function for dfs_set_allow_hw_pulses().
+ * This function called from outside of dfs component.
+ *
+ * Return: void
+ */
+void ucfg_dfs_allow_hw_pulses(struct wlan_objmgr_pdev *pdev,
+			      bool allow_hw_pulses);
+
+/**
+ * ucfg_dfs_is_hw_pulses_allowed() - Check if actual radar detection is allowed
+ * or synthetic pulse detection is enabled.
+ * @pdev: Pointer to DFS pdev object.
+ *
+ * Wrapper function for dfs_is_hw_pulses_allowed().
+ * This function called from outside of dfs component.
+ *
+ * Return: bool
+ */
+bool ucfg_dfs_is_hw_pulses_allowed(struct wlan_objmgr_pdev *pdev);
+#else
+static inline
+void ucfg_dfs_allow_hw_pulses(struct wlan_objmgr_pdev *pdev,
+			      bool allow_hw_pulses)
+{
+}
+
+static inline
+bool ucfg_dfs_is_hw_pulses_allowed(struct wlan_objmgr_pdev *pdev)
+{
+	return true;
+}
+#endif
+
 /**
  * ucfg_dfs_get_override_status_timeout() - Get the value of host dfs status
  * wait timeout.
diff --git a/umac/dfs/dispatcher/src/wlan_dfs_ucfg_api.c b/umac/dfs/dispatcher/src/wlan_dfs_ucfg_api.c
index 1709fe1..2f284b4 100644
--- a/umac/dfs/dispatcher/src/wlan_dfs_ucfg_api.c
+++ b/umac/dfs/dispatcher/src/wlan_dfs_ucfg_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -310,3 +310,42 @@
 
 qdf_export_symbol(ucfg_dfs_get_override_status_timeout);
 #endif
+
+#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(WLAN_DFS_SYNTHETIC_RADAR)
+void ucfg_dfs_allow_hw_pulses(struct wlan_objmgr_pdev *pdev,
+			      bool allow_hw_pulses)
+{
+	struct wlan_dfs *dfs;
+
+	if (!tgt_dfs_is_pdev_5ghz(pdev))
+		return;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
+		return;
+	}
+
+	dfs_allow_hw_pulses(dfs, allow_hw_pulses);
+}
+
+qdf_export_symbol(ucfg_dfs_allow_hw_pulses);
+
+bool ucfg_dfs_is_hw_pulses_allowed(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_dfs *dfs;
+
+	if (!tgt_dfs_is_pdev_5ghz(pdev))
+		return false;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
+		return  false;
+	}
+
+	return dfs_is_hw_pulses_allowed(dfs);
+}
+
+qdf_export_symbol(ucfg_dfs_is_hw_pulses_allowed);
+#endif
diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
index 764349b..4062353 100644
--- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
+++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
@@ -1267,6 +1267,9 @@
  *                                    timeout.
  * @dfs_reset_spoof_test:             Checks if radar detection is enabled.
  * @dfs_is_disable_radar_marking_set: Check if dis_radar_marking param is set.
+ * @dfs_allow_hw_pulses:              Set or unset dfs_allow_hw_pulses which
+ *                                    allow or disallow HW pulses.
+ * @dfs_is_hw_pulses_allowed:         Check if HW pulses are allowed or not.
  */
 struct wlan_lmac_if_dfs_rx_ops {
 	QDF_STATUS (*dfs_get_radars)(struct wlan_objmgr_pdev *pdev);
@@ -1375,6 +1378,9 @@
 			bool value);
 	QDF_STATUS (*dfs_is_bw_reduction_needed)(struct wlan_objmgr_pdev *pdev,
 			bool *bw_reduce);
+	void (*dfs_allow_hw_pulses)(struct wlan_objmgr_pdev *pdev,
+				    bool allow_hw_pulses);
+	bool (*dfs_is_hw_pulses_allowed)(struct wlan_objmgr_pdev *pdev);
 };
 
 /**
diff --git a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c
index d5ada6a..c4d8433 100644
--- a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c
+++ b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c
@@ -428,6 +428,10 @@
 		utils_dfs_bw_reduce;
 	dfs_rx_ops->dfs_is_bw_reduction_needed =
 		utils_dfs_is_bw_reduce;
+	dfs_rx_ops->dfs_allow_hw_pulses =
+		ucfg_dfs_allow_hw_pulses;
+	dfs_rx_ops->dfs_is_hw_pulses_allowed =
+		ucfg_dfs_is_hw_pulses_allowed;
 
 	register_precac_auto_chan_rx_ops(dfs_rx_ops);