qcacld-3.0: Initial snapshot of ihelium wlan driver

qcacld-3.0: Initial snapshot of ihelium wlan driver
to match code-scanned SU Release 5.0.0.139. This is
open-source version of wlan for next Android release.

Change-Id: Icf598ca97da74f84bea607e4e902d1889806f507
diff --git a/core/hif/src/ce/ce_api.h b/core/hif/src/ce/ce_api.h
new file mode 100644
index 0000000..8bde74d
--- /dev/null
+++ b/core/hif/src/ce/ce_api.h
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef __COPY_ENGINE_API_H__
+#define __COPY_ENGINE_API_H__
+
+#include "ce_main.h"
+/* TBDXXX: Use int return values for consistency with Target */
+
+/* TBDXXX: Perhaps merge Host/Target-->common */
+
+/*
+ * Copy Engine support: low-level Target-side Copy Engine API.
+ * This is a hardware access layer used by code that understands
+ * how to use copy engines.
+ */
+
+/*
+ * A "struct CE_handle *" serves as an opaque pointer-sized
+ * handle to a specific copy engine.
+ */
+struct CE_handle;
+
+/*
+ * "Send Completion" callback type for Send Completion Notification.
+ *
+ * If a Send Completion callback is registered and one or more sends
+ * have completed, the callback is invoked.
+ *
+ * per_ce_send_context is a context supplied by the calling layer
+ * (via ce_send_cb_register). It is associated with a copy engine.
+ *
+ * per_transfer_send_context is context supplied by the calling layer
+ * (via the "send" call).  It may be different for each invocation
+ * of send.
+ *
+ * The buffer parameter is the first byte sent of the first buffer
+ * sent (if more than one buffer).
+ *
+ * nbytes is the number of bytes of that buffer that were sent.
+ *
+ * transfer_id matches the value used when the buffer or
+ * buf_list was sent.
+ *
+ * Implementation note: Pops 1 completed send buffer from Source ring
+ */
+typedef void (*ce_send_cb)(struct CE_handle *copyeng,
+			   void *per_ce_send_context,
+			   void *per_transfer_send_context,
+			   cdf_dma_addr_t buffer,
+			   unsigned int nbytes,
+			   unsigned int transfer_id,
+			   unsigned int sw_index,
+			   unsigned int hw_index,
+			   uint32_t toeplitz_hash_result);
+
+/*
+ * "Buffer Received" callback type for Buffer Received Notification.
+ *
+ * Implementation note: Pops 1 completed recv buffer from Dest ring
+ */
+typedef void (*CE_recv_cb)(struct CE_handle *copyeng,
+		   void *per_CE_recv_context,
+		   void *per_transfer_recv_context,
+		   cdf_dma_addr_t buffer,
+		   unsigned int nbytes,
+		   unsigned int transfer_id,
+		   unsigned int flags);
+
+/*
+ * Copy Engine Watermark callback type.
+ *
+ * Allows upper layers to be notified when watermarks are reached:
+ *   space is available and/or running short in a source ring
+ *   buffers are exhausted and/or abundant in a destination ring
+ *
+ * The flags parameter indicates which condition triggered this
+ * callback.  See CE_WM_FLAG_*.
+ *
+ * Watermark APIs are provided to allow upper layers "batch"
+ * descriptor processing and to allow upper layers to
+ * throttle/unthrottle.
+ */
+typedef void (*CE_watermark_cb)(struct CE_handle *copyeng,
+				void *per_CE_wm_context, unsigned int flags);
+
+#define CE_WM_FLAG_SEND_HIGH   1
+#define CE_WM_FLAG_SEND_LOW    2
+#define CE_WM_FLAG_RECV_HIGH   4
+#define CE_WM_FLAG_RECV_LOW    8
+
+/* A list of buffers to be gathered and sent */
+struct ce_sendlist;
+
+/* Copy Engine settable attributes */
+struct CE_attr;
+
+/*==================Send=====================================================*/
+
+/* ce_send flags */
+/* disable ring's byte swap, even if the default policy is to swap */
+#define CE_SEND_FLAG_SWAP_DISABLE        1
+
+/*
+ * Queue a source buffer to be sent to an anonymous destination buffer.
+ *   copyeng         - which copy engine to use
+ *   buffer          - address of buffer
+ *   nbytes          - number of bytes to send
+ *   transfer_id     - arbitrary ID; reflected to destination
+ *   flags           - CE_SEND_FLAG_* values
+ * Returns 0 on success; otherwise an error status.
+ *
+ * Note: If no flags are specified, use CE's default data swap mode.
+ *
+ * Implementation note: pushes 1 buffer to Source ring
+ */
+int ce_send(struct CE_handle *copyeng,
+		void *per_transfer_send_context,
+		cdf_dma_addr_t buffer,
+		unsigned int nbytes,
+		unsigned int transfer_id,
+		unsigned int flags,
+		unsigned int user_flags);
+
+#ifdef WLAN_FEATURE_FASTPATH
+int ce_send_fast(struct CE_handle *copyeng, cdf_nbuf_t *msdus,
+		 unsigned int num_msdus, unsigned int transfer_id);
+
+#endif
+void ce_pkt_dl_len_set(void *hif_sc, unsigned int pkt_download_len);
+
+/*
+ * Register a Send Callback function.
+ * This function is called as soon as the contents of a Send
+ * have reached the destination, unless disable_interrupts is
+ * requested.  In this case, the callback is invoked when the
+ * send status is polled, shortly after the send completes.
+ */
+void ce_send_cb_register(struct CE_handle *copyeng,
+			 ce_send_cb fn_ptr,
+			 void *per_ce_send_context, int disable_interrupts);
+
+/*
+ * Return the size of a SendList. This allows the caller to allocate
+ * a SendList while the SendList structure remains opaque.
+ */
+unsigned int ce_sendlist_sizeof(void);
+
+/* Initialize a sendlist */
+void ce_sendlist_init(struct ce_sendlist *sendlist);
+
+/* Append a simple buffer (address/length) to a sendlist. */
+int ce_sendlist_buf_add(struct ce_sendlist *sendlist,
+		cdf_dma_addr_t buffer,
+		unsigned int nbytes,
+		uint32_t flags, /* OR-ed with internal flags */
+		uint32_t user_flags);
+
+/*
+ * Queue a "sendlist" of buffers to be sent using gather to a single
+ * anonymous destination buffer
+ *   copyeng         - which copy engine to use
+ *   sendlist        - list of simple buffers to send using gather
+ *   transfer_id     - arbitrary ID; reflected to destination
+ * Returns 0 on success; otherwise an error status.
+ *
+ * Implemenation note: Pushes multiple buffers with Gather to Source ring.
+ */
+int ce_sendlist_send(struct CE_handle *copyeng,
+		void *per_transfer_send_context,
+		struct ce_sendlist *sendlist,
+		unsigned int transfer_id);
+
+/*==================Recv=====================================================*/
+
+/*
+ * Make a buffer available to receive. The buffer must be at least of a
+ * minimal size appropriate for this copy engine (src_sz_max attribute).
+ *   copyeng                    - which copy engine to use
+ *   per_transfer_recv_context  - context passed back to caller's recv_cb
+ *   buffer                     - address of buffer in CE space
+ * Returns 0 on success; otherwise an error status.
+ *
+ * Implemenation note: Pushes a buffer to Dest ring.
+ */
+int ce_recv_buf_enqueue(struct CE_handle *copyeng,
+			void *per_transfer_recv_context,
+			cdf_dma_addr_t buffer);
+
+/*
+ * Register a Receive Callback function.
+ * This function is called as soon as data is received
+ * from the source.
+ */
+void ce_recv_cb_register(struct CE_handle *copyeng,
+			 CE_recv_cb fn_ptr,
+			 void *per_CE_recv_context,
+			 int disable_interrupts);
+
+/*==================CE Watermark=============================================*/
+
+/*
+ * Register a Watermark Callback function.
+ * This function is called as soon as a watermark level
+ * is crossed.  A Watermark Callback function is free to
+ * handle received data "en masse"; but then some coordination
+ * is required with a registered Receive Callback function.
+ * [Suggestion: Either handle Receives in a Receive Callback
+ * or en masse in a Watermark Callback; but not both.]
+ */
+void ce_watermark_cb_register(struct CE_handle *copyeng,
+			  CE_watermark_cb fn_ptr,
+			  void *per_CE_wm_context);
+
+/*
+ * Set low/high watermarks for the send/source side of a copy engine.
+ *
+ * Typically, the destination side CPU manages watermarks for
+ * the receive side and the source side CPU manages watermarks
+ * for the send side.
+ *
+ * A low watermark of 0 is never hit (so the watermark function
+ * will never be called for a Low Watermark condition).
+ *
+ * A high watermark equal to nentries is never hit (so the
+ * watermark function will never be called for a High Watermark
+ * condition).
+ */
+void ce_send_watermarks_set(struct CE_handle *copyeng,
+			    unsigned int low_alert_nentries,
+			    unsigned int high_alert_nentries);
+
+/* Set low/high watermarks for the receive/destination side of copy engine. */
+void ce_recv_watermarks_set(struct CE_handle *copyeng,
+			    unsigned int low_alert_nentries,
+			    unsigned int high_alert_nentries);
+
+/*
+ * Return the number of entries that can be queued
+ * to a ring at an instant in time.
+ *
+ * For source ring, does not imply that destination-side
+ * buffers are available; merely indicates descriptor space
+ * in the source ring.
+ *
+ * For destination ring, does not imply that previously
+ * received buffers have been processed; merely indicates
+ * descriptor space in destination ring.
+ *
+ * Mainly for use with CE Watermark callback.
+ */
+unsigned int ce_send_entries_avail(struct CE_handle *copyeng);
+unsigned int ce_recv_entries_avail(struct CE_handle *copyeng);
+
+/*
+ * Return the number of entries in the ring that are ready
+ * to be processed by software.
+ *
+ * For source ring, the number of descriptors that have
+ * been completed and can now be overwritten with new send
+ * descriptors.
+ *
+ * For destination ring, the number of descriptors that
+ * are available to be processed (newly received buffers).
+ */
+unsigned int ce_send_entries_done(struct CE_handle *copyeng);
+unsigned int ce_recv_entries_done(struct CE_handle *copyeng);
+
+/* recv flags */
+/* Data is byte-swapped */
+#define CE_RECV_FLAG_SWAPPED            1
+
+void ce_enable_msi(struct ol_softc *scn,
+		   unsigned int CE_id,
+		   uint32_t msi_addr_lo,
+		   uint32_t msi_addr_hi,
+		   uint32_t msi_data);
+/*
+ * Supply data for the next completed unprocessed receive descriptor.
+ *
+ * For use
+ *    with CE Watermark callback,
+ *    in a recv_cb function when processing buf_lists
+ *    in a recv_cb function in order to mitigate recv_cb's.
+ *
+ * Implemenation note: Pops buffer from Dest ring.
+ */
+int ce_completed_recv_next(struct CE_handle *copyeng,
+			   void **per_CE_contextp,
+			   void **per_transfer_contextp,
+			   cdf_dma_addr_t *bufferp,
+			   unsigned int *nbytesp,
+			   unsigned int *transfer_idp,
+			   unsigned int *flagsp);
+
+/*
+ * Supply data for the next completed unprocessed send descriptor.
+ *
+ * For use
+ *    with CE Watermark callback
+ *    in a send_cb function in order to mitigate send_cb's.
+ *
+ * Implementation note: Pops 1 completed send buffer from Source ring
+ */
+int ce_completed_send_next(struct CE_handle *copyeng,
+			   void **per_CE_contextp,
+			   void **per_transfer_contextp,
+			   cdf_dma_addr_t *bufferp,
+			   unsigned int *nbytesp,
+			   unsigned int *transfer_idp,
+			   unsigned int *sw_idx,
+			   unsigned int *hw_idx,
+			   uint32_t *toeplitz_hash_result);
+
+/*==================CE Engine Initialization=================================*/
+
+/* Initialize an instance of a CE */
+struct CE_handle *ce_init(struct ol_softc *scn,
+			  unsigned int CE_id, struct CE_attr *attr);
+
+/*==================CE Engine Shutdown=======================================*/
+/*
+ * Support clean shutdown by allowing the caller to revoke
+ * receive buffers.  Target DMA must be stopped before using
+ * this API.
+ */
+CDF_STATUS
+ce_revoke_recv_next(struct CE_handle *copyeng,
+		    void **per_CE_contextp,
+		    void **per_transfer_contextp,
+		    cdf_dma_addr_t *bufferp);
+
+/*
+ * Support clean shutdown by allowing the caller to cancel
+ * pending sends.  Target DMA must be stopped before using
+ * this API.
+ */
+CDF_STATUS
+ce_cancel_send_next(struct CE_handle *copyeng,
+		    void **per_CE_contextp,
+		    void **per_transfer_contextp,
+		    cdf_dma_addr_t *bufferp,
+		    unsigned int *nbytesp,
+		    unsigned int *transfer_idp,
+		    uint32_t *toeplitz_hash_result);
+
+void ce_fini(struct CE_handle *copyeng);
+
+/*==================CE Interrupt Handlers====================================*/
+void ce_per_engine_service_any(int irq, struct ol_softc *scn);
+int ce_per_engine_service(struct ol_softc *scn, unsigned int CE_id);
+void ce_per_engine_servicereap(struct ol_softc *scn, unsigned int CE_id);
+
+/*===================CE cmpl interrupt Enable/Disable =======================*/
+void ce_disable_any_copy_compl_intr(struct ol_softc *scn);
+void ce_enable_any_copy_compl_intr(struct ol_softc *scn);
+void ce_disable_any_copy_compl_intr_nolock(struct ol_softc *scn);
+void ce_enable_any_copy_compl_intr_nolock(struct ol_softc *scn);
+
+/* API to check if any of the copy engine pipes has
+ * pending frames for prcoessing
+ */
+bool ce_get_rx_pending(struct ol_softc *scn);
+
+/* CE_attr.flags values */
+#define CE_ATTR_NO_SNOOP             0x01 /* Use NonSnooping PCIe accesses? */
+#define CE_ATTR_BYTE_SWAP_DATA       0x02 /* Byte swap data words */
+#define CE_ATTR_SWIZZLE_DESCRIPTORS  0x04 /* Swizzle descriptors? */
+#define CE_ATTR_DISABLE_INTR         0x08 /* no interrupt on copy completion */
+#define CE_ATTR_ENABLE_POLL          0x10 /* poll for residue descriptors */
+
+/* Attributes of an instance of a Copy Engine */
+struct CE_attr {
+	unsigned int flags;         /* CE_ATTR_* values */
+	unsigned int priority;      /* TBD */
+	unsigned int src_nentries;  /* #entries in source ring -
+				     * Must be a power of 2 */
+	unsigned int src_sz_max;    /* Max source send size for this CE.
+				     * This is also the minimum size of
+				     * a destination buffer. */
+	unsigned int dest_nentries; /* #entries in destination ring -
+				     * Must be a power of 2 */
+	void *reserved;             /* Future use */
+};
+
+/*
+ * When using sendlist_send to transfer multiple buffer fragments, the
+ * transfer context of each fragment, except last one, will be filled
+ * with CE_SENDLIST_ITEM_CTXT. CE_completed_send will return success for
+ * each fragment done with send and the transfer context would be
+ * CE_SENDLIST_ITEM_CTXT. Upper layer could use this to identify the
+ * status of a send completion.
+ */
+#define CE_SENDLIST_ITEM_CTXT   ((void *)0xcecebeef)
+
+/*
+ * This is an opaque type that is at least large enough to hold
+ * a sendlist. A sendlist can only be accessed through CE APIs,
+ * but this allows a sendlist to be allocated on the run-time
+ * stack.  TBDXXX: un-opaque would be simpler...
+ */
+struct ce_sendlist {
+	unsigned int word[62];
+};
+
+#define ATH_ISR_NOSCHED  0x0000  /* Do not schedule bottom half/DPC */
+#define ATH_ISR_SCHED    0x0001  /* Schedule the bottom half for execution */
+#define ATH_ISR_NOTMINE  0x0002  /* for shared IRQ's */
+
+#ifdef IPA_OFFLOAD
+/*
+ * Copy engine should release resource to micro controller
+ * Micro controller needs
+   - Copy engine source descriptor base address
+   - Copy engine source descriptor size
+   - PCI BAR address to access copy engine regiser
+ */
+void ce_ipa_get_resource(struct CE_handle *ce,
+			 uint32_t *ce_sr_base_paddr,
+			 uint32_t *ce_sr_ring_size,
+			 cdf_dma_addr_t *ce_reg_paddr);
+#else
+static inline void ce_ipa_get_resource(struct CE_handle *ce,
+			 uint32_t *ce_sr_base_paddr,
+			 uint32_t *ce_sr_ring_size,
+			 cdf_dma_addr_t *ce_reg_paddr)
+{
+	return;
+}
+#endif /* IPA_OFFLOAD */
+
+static inline void ce_pkt_error_count_incr(
+	struct HIF_CE_state *_hif_state,
+	enum ol_ath_hif_pkt_ecodes _hif_ecode)
+{
+	if (_hif_ecode == HIF_PIPE_NO_RESOURCE)
+		(_hif_state->scn->pkt_stats.hif_pipe_no_resrc_count)
+		+= 1;
+}
+
+int hif_completion_thread(struct HIF_CE_state *hif_state);
+bool ce_check_rx_pending(struct ol_softc *scn, int ce_id);
+#if defined(FEATURE_LRO)
+void ce_lro_flush_cb_register(struct ol_softc *scn,
+	 void (handler)(void *), void *data);
+#endif
+#endif /* __COPY_ENGINE_API_H__ */
diff --git a/core/hif/src/ce/ce_assignment.h b/core/hif/src/ce/ce_assignment.h
new file mode 100644
index 0000000..b493d55
--- /dev/null
+++ b/core/hif/src/ce/ce_assignment.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+/*
+ * Implementation of the Host-side Host InterFace (HIF) API
+ * for a Host/Target interconnect using Copy Engines over PCIe.
+ */
+
+#ifndef __HIF_PCI_INTERNAL_H__
+#define __HIF_PCI_INTERNAL_H__
+
+#define HIF_PCI_DEBUG   ATH_DEBUG_MAKE_MODULE_MASK(0)
+#define HIF_PCI_IPA_UC_ASSIGNED_CE  5
+
+#if defined(DEBUG)
+static ATH_DEBUG_MASK_DESCRIPTION g_hif_debug_description[] = {
+	{HIF_PCI_DEBUG, "hif_pci"},
+};
+
+ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif, "hif", "PCIe Host Interface",
+				ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO,
+				ATH_DEBUG_DESCRIPTION_COUNT
+					 (g_hif_debug_description),
+				 g_hif_debug_description);
+#endif
+
+#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
+spinlock_t pcie_access_log_lock;
+unsigned int pcie_access_log_seqnum = 0;
+HIF_ACCESS_LOG pcie_access_log[PCIE_ACCESS_LOG_NUM];
+static void hif_target_dump_access_log(void);
+#endif
+
+/*
+ * Host software's Copy Engine configuration.
+ * This table is derived from the CE_PCI TABLE, above.
+ */
+#ifdef BIG_ENDIAN_HOST
+#define CE_ATTR_FLAGS CE_ATTR_BYTE_SWAP_DATA
+#else
+#define CE_ATTR_FLAGS 0
+#endif
+
+/* Maximum number of Copy Engine's supported */
+#define CE_HTT_H2T_MSG_SRC_NENTRIES 2048
+
+#define DIAG_CE_ID           7
+#define EPPING_CE_FLAGS_POLL \
+	(CE_ATTR_DISABLE_INTR|CE_ATTR_ENABLE_POLL|CE_ATTR_FLAGS)
+#ifdef QCA_WIFI_3_0
+static struct CE_attr host_ce_config_wlan[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ CE_ATTR_FLAGS, 0, 16, 2048, 0, NULL,},
+	/* target->host HTT + HTC control */
+	{ /* CE1 */ CE_ATTR_FLAGS, 0, 0,  2048, 512, NULL,},
+	/* target->host WMI */
+	{ /* CE2 */ CE_ATTR_FLAGS, 0, 0,  2048, 32, NULL,},
+	/* host->target WMI */
+	{ /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL,},
+	/* host->target HTT */
+	{ /* CE4 */ (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,
+		CE_HTT_H2T_MSG_SRC_NENTRIES, 256, 0, NULL,},
+	/* ipa_uc->target HTC control */
+	{ /* CE5 */ (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,
+		1024, 512, 0, NULL,},
+	/* Target autonomous HIF_memcpy */
+	{ /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,},
+	/* ce_diag, the Diagnostic Window */
+	{ /* CE7 */ (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,
+		2, DIAG_TRANSFER_LIMIT, 2, NULL,},
+};
+
+static struct CE_pipe_config target_ce_config_wlan[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ 0, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,},
+	/* target->host HTT */
+	{ /* CE1 */ 1, PIPEDIR_IN,  32, 2048, CE_ATTR_FLAGS, 0,},
+	/* target->host WMI  + HTC control */
+	{ /* CE2 */ 2, PIPEDIR_IN,  32, 2048, CE_ATTR_FLAGS, 0,},
+	/* host->target WMI */
+	{ /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,},
+	/* host->target HTT */
+	{ /* CE4 */ 4, PIPEDIR_OUT, 256, 256,
+		(CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,},
+	/* NB: 50% of src nentries, since tx has 2 frags */
+	/* ipa_uc->target */
+	{ /* CE5 */ 5, PIPEDIR_OUT, 1024,   64,
+		(CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,},
+	/* Reserved for target autonomous HIF_memcpy */
+	{ /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0,},
+	/* CE7 used only by Host */
+	{ /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0,
+		(CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,},
+	/* CE8 used only by IPA */
+	{ /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}
+};
+
+static struct CE_attr host_ce_config_wlan_epping_poll[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ CE_ATTR_FLAGS, 0, 16, 2048, 0, NULL,},
+	/* target->host EP-ping */
+	{ /* CE1 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,},
+	/* target->host EP-ping */
+	{ /* CE2 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,},
+	/* host->target EP-ping */
+	{ /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,},
+	/* host->target EP-ping */
+	{ /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,},
+	/* EP-ping heartbeat */
+	{ /* CE5 */ CE_ATTR_FLAGS, 0, 0,   2048, 128, NULL,},
+	/* unused */
+	{ /* CE6 */ CE_ATTR_FLAGS, 0, 0,   0, 0, NULL,},
+	/* ce_diag, the Diagnostic Window */
+	{ /* CE7 */ CE_ATTR_FLAGS, 0, 2,   DIAG_TRANSFER_LIMIT, 2, NULL,},
+};
+
+static struct CE_attr host_ce_config_wlan_epping_irq[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ CE_ATTR_FLAGS, 0,  16, 2048, 0, NULL,},
+	/* target->host EP-ping */
+	{ /* CE1 */ CE_ATTR_FLAGS, 0,   0, 2048, 128, NULL,},
+	/* target->host EP-ping */
+	{ /* CE2 */ CE_ATTR_FLAGS, 0,   0, 2048, 128, NULL,},
+	/* host->target EP-ping */
+	{ /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,},
+	/* host->target EP-ping */
+	{ /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,},
+	/* EP-ping heartbeat */
+	{ /* CE5 */ CE_ATTR_FLAGS, 0,   0, 2048, 128, NULL,},
+	/* unused */
+	{ /* CE6 */ CE_ATTR_FLAGS, 0,   0, 0, 0, NULL,},
+	/* ce_diag, the Diagnostic Window */
+	{ /* CE7 */ CE_ATTR_FLAGS, 0,   2, DIAG_TRANSFER_LIMIT, 2, NULL,},
+};
+/*
+ * EP-ping firmware's CE configuration
+ */
+static struct CE_pipe_config target_ce_config_wlan_epping[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ 0, PIPEDIR_OUT,  16, 2048, CE_ATTR_FLAGS, 0,},
+	/* target->host EP-ping */
+	{ /* CE1 */ 1, PIPEDIR_IN,  128, 2048, CE_ATTR_FLAGS, 0,},
+	/* target->host EP-ping */
+	{ /* CE2 */ 2, PIPEDIR_IN,  128, 2048, CE_ATTR_FLAGS, 0,},
+	/* host->target EP-ping */
+	{ /* CE3 */ 3, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,},
+	/* host->target EP-ping */
+	{ /* CE4 */ 4, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,},
+	/* EP-ping heartbeat */
+	{ /* CE5 */ 5, PIPEDIR_IN,  128, 2048, CE_ATTR_FLAGS, 0,},
+	/* unused */
+	{ /* CE6 */ 6, PIPEDIR_INOUT, 0, 0, CE_ATTR_FLAGS, 0,},
+	/* CE7 used only by Host */
+	{ /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,},
+	/* CE8 used only by IPA */
+	{ /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}
+};
+#else
+static struct CE_attr host_ce_config_wlan[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ CE_ATTR_FLAGS, 0, 16,  256, 0, NULL,},
+	/* target->host HTT + HTC control */
+	{ /* CE1 */ CE_ATTR_FLAGS, 0, 0,  2048, 512, NULL,},
+	/* target->host WMI */
+	{ /* CE2 */ CE_ATTR_FLAGS, 0, 0,  2048, 32, NULL,},
+	/* host->target WMI */
+	{ /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL,},
+	/* host->target HTT */
+	{ /* CE4 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, 0,
+		CE_HTT_H2T_MSG_SRC_NENTRIES, 256, 0, NULL,},
+	/* ipa_uc->target HTC control */
+	{ /* CE5 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, 0,
+		1024, 512, 0, NULL,},
+	/* Target autonomous HIF_memcpy */
+	{ /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,},
+	/* ce_diag, the Diagnostic Window */
+	{ /* CE7 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR,
+		0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,},
+};
+
+static struct CE_pipe_config target_ce_config_wlan[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ 0, PIPEDIR_OUT, 32,  256, CE_ATTR_FLAGS, 0,},
+	/* target->host HTT + HTC control */
+	{ /* CE1 */ 1, PIPEDIR_IN, 32,  2048, CE_ATTR_FLAGS, 0,},
+	/* target->host WMI */
+	{ /* CE2 */ 2, PIPEDIR_IN, 32,  2048, CE_ATTR_FLAGS, 0,},
+	/* host->target WMI */
+	{ /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,},
+	/* host->target HTT */
+	{ /* CE4 */ 4, PIPEDIR_OUT, 256, 256, CE_ATTR_FLAGS, 0,},
+	/* NB: 50% of src nentries, since tx has 2 frags */
+	/* ipa_uc->target HTC control */
+	{ /* CE5 */ 5, PIPEDIR_OUT, 1024,   64, CE_ATTR_FLAGS, 0,},
+	/* Reserved for target autonomous HIF_memcpy */
+	{ /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0,},
+	/* CE7 used only by Host */
+	{ /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,},
+	/* CE8 used only by IPA */
+	{ /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}
+};
+
+static struct CE_attr host_ce_config_wlan_epping_poll[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,},
+	/* target->host EP-ping */
+	{ /* CE1 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,},
+	/* target->host EP-ping */
+	{ /* CE2 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,},
+	/* host->target EP-ping */
+	{ /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,},
+	/* host->target EP-ping */
+	{ /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,},
+	/* EP-ping heartbeat */
+	{ /* CE5 */ CE_ATTR_FLAGS, 0, 0,   2048, 128, NULL,},
+	/* unused */
+	{ /* CE6 */ CE_ATTR_FLAGS, 0, 0,   0, 0, NULL,},
+	/* ce_diag, the Diagnostic Window */
+	{ /* CE7 */ CE_ATTR_FLAGS, 0, 2,   DIAG_TRANSFER_LIMIT, 2, NULL,},
+};
+static struct CE_attr host_ce_config_wlan_epping_irq[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,},
+	/* target->host EP-ping */
+	{ /* CE1 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,},
+	/* target->host EP-ping */
+	{ /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,},
+	/* host->target EP-ping */
+	{ /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,},
+	/* host->target EP-ping */
+	{ /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,},
+	/* EP-ping heartbeat */
+	{ /* CE5 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,},
+	/* unused */
+	{ /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,},
+	/* ce_diag, the Diagnostic Window */
+	{ /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,},
+};
+/*
+ * EP-ping firmware's CE configuration
+ */
+static struct CE_pipe_config target_ce_config_wlan_epping[] = {
+	/* host->target HTC control and raw streams */
+	{ /* CE0 */ 0, PIPEDIR_OUT, 16,   256, CE_ATTR_FLAGS, 0,},
+	/* target->host EP-ping */
+	{ /* CE1 */ 1, PIPEDIR_IN, 128,  2048, CE_ATTR_FLAGS, 0,},
+	/* target->host EP-ping */
+	{ /* CE2 */ 2, PIPEDIR_IN, 128,  2048, CE_ATTR_FLAGS, 0,},
+	/* host->target EP-ping */
+	{ /* CE3 */ 3, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,},
+	/* host->target EP-ping */
+	{ /* CE4 */ 4, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,},
+	/* EP-ping heartbeat */
+	{ /* CE5 */ 5, PIPEDIR_IN, 128,  2048, CE_ATTR_FLAGS, 0,},
+	/* unused */
+	{ /* CE6 */ 6, PIPEDIR_INOUT, 0, 0, CE_ATTR_FLAGS, 0,},
+	/* CE7 used only by Host */
+	{ /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,},
+	/* CE8 used only by IPA */
+	{ /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}
+};
+#endif
+
+static struct CE_attr *host_ce_config = host_ce_config_wlan;
+static struct CE_pipe_config *target_ce_config = target_ce_config_wlan;
+static int target_ce_config_sz = sizeof(target_ce_config_wlan);
+#endif /* __HIF_PCI_INTERNAL_H__ */
diff --git a/core/hif/src/ce/ce_bmi.c b/core/hif/src/ce/ce_bmi.c
new file mode 100644
index 0000000..b2d541d
--- /dev/null
+++ b/core/hif/src/ce/ce_bmi.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#include <osdep.h>
+#include "a_types.h"
+#include "athdefs.h"
+#include "osapi_linux.h"
+#include "targcfg.h"
+#include "cdf_lock.h"
+#include "cdf_status.h"
+#include <cdf_atomic.h>         /* cdf_atomic_read */
+#include <targaddrs.h>
+#include <bmi_msg.h>
+#include "hif_io32.h"
+#include <hif.h>
+#include "regtable.h"
+#define ATH_MODULE_NAME hif
+#include <a_debug.h>
+#include "hif_main.h"
+#include "ce_api.h"
+#include "cdf_trace.h"
+#include "cds_api.h"
+#ifdef CONFIG_CNSS
+#include <net/cnss.h>
+#else
+#include "cnss_stub.h"
+#endif
+#include <cds_get_bin.h>
+#include "epping_main.h"
+#include "hif_debug.h"
+
+/* Track a BMI transaction that is in progress */
+#ifndef BIT
+#define BIT(n) (1 << (n))
+#endif
+
+enum {
+	BMI_REQ_SEND_DONE = BIT(0),   /* the bmi tx completion */
+	BMI_RESP_RECV_DONE = BIT(1),  /* the bmi respond is received */
+};
+
+struct BMI_transaction {
+	struct HIF_CE_state *hif_state;
+	cdf_semaphore_t bmi_transaction_sem;
+	uint8_t *bmi_request_host;        /* Req BMI msg in Host addr space */
+	cdf_dma_addr_t bmi_request_CE;    /* Req BMI msg in CE addr space */
+	uint32_t bmi_request_length;      /* Length of BMI request */
+	uint8_t *bmi_response_host;       /* Rsp BMI msg in Host addr space */
+	cdf_dma_addr_t bmi_response_CE;   /* Rsp BMI msg in CE addr space */
+	unsigned int bmi_response_length; /* Length of received response */
+	unsigned int bmi_timeout_ms;
+	uint32_t bmi_transaction_flags;   /* flags for the transcation */
+};
+
+/*
+ * send/recv completion functions for BMI.
+ * NB: The "net_buf" parameter is actually just a
+ * straight buffer, not an sk_buff.
+ */
+void hif_bmi_send_done(struct CE_handle *copyeng, void *ce_context,
+		  void *transfer_context, cdf_dma_addr_t data,
+		  unsigned int nbytes,
+		  unsigned int transfer_id, unsigned int sw_index,
+		  unsigned int hw_index, uint32_t toeplitz_hash_result)
+{
+	struct BMI_transaction *transaction =
+		(struct BMI_transaction *)transfer_context;
+	struct ol_softc *scn = transaction->hif_state->scn;
+
+#ifdef BMI_RSP_POLLING
+	/*
+	 * Fix EV118783, Release a semaphore after sending
+	 * no matter whether a response is been expecting now.
+	 */
+	cdf_semaphore_release(scn->cdf_dev,
+			      &transaction->bmi_transaction_sem);
+#else
+	/*
+	 * If a response is anticipated, we'll complete the
+	 * transaction if the response has been received.
+	 * If no response is anticipated, complete the
+	 * transaction now.
+	 */
+	transaction->bmi_transaction_flags |= BMI_REQ_SEND_DONE;
+
+	/* resp is't needed or has already been received,
+	 * never assume resp comes later then this */
+	if (!transaction->bmi_response_CE ||
+	    (transaction->bmi_transaction_flags & BMI_RESP_RECV_DONE)) {
+		cdf_semaphore_release(scn->cdf_dev,
+				      &transaction->bmi_transaction_sem);
+	}
+#endif
+}
+
+#ifndef BMI_RSP_POLLING
+void hif_bmi_recv_data(struct CE_handle *copyeng, void *ce_context,
+		  void *transfer_context, cdf_dma_addr_t data,
+		  unsigned int nbytes,
+		  unsigned int transfer_id, unsigned int flags)
+{
+	struct BMI_transaction *transaction =
+		(struct BMI_transaction *)transfer_context;
+	struct ol_softc *scn = transaction->hif_state->scn;
+
+	transaction->bmi_response_length = nbytes;
+	transaction->bmi_transaction_flags |= BMI_RESP_RECV_DONE;
+
+	/* when both send/recv are done, the sem can be released */
+	if (transaction->bmi_transaction_flags & BMI_REQ_SEND_DONE) {
+		cdf_semaphore_release(scn->cdf_dev,
+				      &transaction->bmi_transaction_sem);
+	}
+}
+#endif
+
+CDF_STATUS hif_exchange_bmi_msg(struct ol_softc *scn,
+		     uint8_t *bmi_request,
+		     uint32_t request_length,
+		     uint8_t *bmi_response,
+		     uint32_t *bmi_response_lengthp, uint32_t TimeoutMS)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	struct HIF_CE_pipe_info *send_pipe_info =
+		&(hif_state->pipe_info[BMI_CE_NUM_TO_TARG]);
+	struct CE_handle *ce_send_hdl = send_pipe_info->ce_hdl;
+	cdf_dma_addr_t CE_request, CE_response = 0;
+	struct BMI_transaction *transaction = NULL;
+	int status = CDF_STATUS_SUCCESS;
+	struct HIF_CE_pipe_info *recv_pipe_info =
+		&(hif_state->pipe_info[BMI_CE_NUM_TO_HOST]);
+	struct CE_handle *ce_recv = recv_pipe_info->ce_hdl;
+	unsigned int mux_id = 0;
+	unsigned int transaction_id = 0xffff;
+	unsigned int user_flags = 0;
+#ifdef BMI_RSP_POLLING
+	cdf_dma_addr_t buf;
+	unsigned int completed_nbytes, id, flags;
+	int i;
+#endif
+
+	transaction =
+		(struct BMI_transaction *)cdf_mem_malloc(sizeof(*transaction));
+	if (unlikely(!transaction)) {
+		HIF_ERROR("%s: no memory", __func__);
+		return CDF_STATUS_E_NOMEM;
+	}
+	transaction_id = (mux_id & MUX_ID_MASK) |
+		(transaction_id & TRANSACTION_ID_MASK);
+#ifdef QCA_WIFI_3_0
+	user_flags &= DESC_DATA_FLAG_MASK;
+#endif
+	A_TARGET_ACCESS_LIKELY(scn);
+
+	/* Initialize bmi_transaction_sem to block */
+	cdf_semaphore_init(&transaction->bmi_transaction_sem);
+	cdf_semaphore_acquire(scn->cdf_dev, &transaction->bmi_transaction_sem);
+
+	transaction->hif_state = hif_state;
+	transaction->bmi_request_host = bmi_request;
+	transaction->bmi_request_length = request_length;
+	transaction->bmi_response_length = 0;
+	transaction->bmi_timeout_ms = TimeoutMS;
+	transaction->bmi_transaction_flags = 0;
+
+	/*
+	 * CE_request = dma_map_single(dev,
+	 * (void *)bmi_request, request_length, DMA_TO_DEVICE);
+	 */
+	CE_request = scn->bmi_cmd_da;
+	transaction->bmi_request_CE = CE_request;
+
+	if (bmi_response) {
+
+		/*
+		 * CE_response = dma_map_single(dev, bmi_response,
+		 * BMI_DATASZ_MAX, DMA_FROM_DEVICE);
+		 */
+		CE_response = scn->bmi_rsp_da;
+		transaction->bmi_response_host = bmi_response;
+		transaction->bmi_response_CE = CE_response;
+		/* dma_cache_sync(dev, bmi_response,
+		    BMI_DATASZ_MAX, DMA_FROM_DEVICE); */
+		cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev,
+					       CE_response,
+					       BMI_DATASZ_MAX,
+					       DMA_FROM_DEVICE);
+		ce_recv_buf_enqueue(ce_recv, transaction,
+				    transaction->bmi_response_CE);
+		/* NB: see HIF_BMI_recv_done */
+	} else {
+		transaction->bmi_response_host = NULL;
+		transaction->bmi_response_CE = 0;
+	}
+
+	/* dma_cache_sync(dev, bmi_request, request_length, DMA_TO_DEVICE); */
+	cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_request,
+				       request_length, DMA_TO_DEVICE);
+
+	status =
+		ce_send(ce_send_hdl, transaction,
+			CE_request, request_length,
+			transaction_id, 0, user_flags);
+	ASSERT(status == CDF_STATUS_SUCCESS);
+	/* NB: see hif_bmi_send_done */
+
+	/* TBDXXX: handle timeout */
+
+	/* Wait for BMI request/response transaction to complete */
+	/* Always just wait for BMI request here if
+	 * BMI_RSP_POLLING is defined */
+	while (cdf_semaphore_acquire
+		       (scn->cdf_dev, &transaction->bmi_transaction_sem)) {
+		/*need some break out condition(time out?) */
+	}
+
+	if (bmi_response) {
+#ifdef BMI_RSP_POLLING
+		/* Fix EV118783, do not wait a semaphore for the BMI response
+		 * since the relative interruption may be lost.
+		 * poll the BMI response instead.
+		 */
+		i = 0;
+		while (ce_completed_recv_next(
+			    ce_recv, NULL, NULL, &buf,
+			    &completed_nbytes, &id,
+			    &flags) != CDF_STATUS_SUCCESS) {
+			if (i++ > BMI_RSP_TO_MILLISEC) {
+				HIF_ERROR("%s:error, can't get bmi response\n",
+					__func__);
+				status = CDF_STATUS_E_BUSY;
+				break;
+			}
+			OS_DELAY(1000);
+		}
+
+		if ((status == CDF_STATUS_SUCCESS) && bmi_response_lengthp)
+			*bmi_response_lengthp = completed_nbytes;
+#else
+		if ((status == CDF_STATUS_SUCCESS) && bmi_response_lengthp) {
+			*bmi_response_lengthp =
+				transaction->bmi_response_length;
+		}
+#endif
+
+	}
+
+	/* dma_unmap_single(dev, transaction->bmi_request_CE,
+		request_length, DMA_TO_DEVICE); */
+	/* bus_unmap_single(scn->sc_osdev,
+		 transaction->bmi_request_CE,
+		request_length, BUS_DMA_TODEVICE); */
+
+	if (status != CDF_STATUS_SUCCESS) {
+		cdf_dma_addr_t unused_buffer;
+		unsigned int unused_nbytes;
+		unsigned int unused_id;
+		unsigned int toeplitz_hash_result;
+
+		ce_cancel_send_next(ce_send_hdl,
+			NULL, NULL, &unused_buffer,
+			&unused_nbytes, &unused_id,
+			&toeplitz_hash_result);
+	}
+
+	A_TARGET_ACCESS_UNLIKELY(scn);
+	cdf_mem_free(transaction);
+	return status;
+}
diff --git a/core/hif/src/ce/ce_bmi.h b/core/hif/src/ce/ce_bmi.h
new file mode 100644
index 0000000..c09b211
--- /dev/null
+++ b/core/hif/src/ce/ce_bmi.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef __CE_BMI_H__
+#define __CE_BMI_H__
+
+#include <cdf_atomic.h>         /* cdf_atomic_read */
+#include "cdf_lock.h"
+#include "ce_api.h"
+#include "cepci.h"
+
+void hif_bmi_recv_data(struct CE_handle *copyeng, void *ce_context,
+		  void *transfer_context, cdf_dma_addr_t data,
+		  unsigned int nbytes,
+		  unsigned int transfer_id, unsigned int flags);
+void hif_bmi_send_done(struct CE_handle *copyeng, void *ce_context,
+		  void *transfer_context, cdf_dma_addr_t data,
+		  unsigned int nbytes,
+		  unsigned int transfer_id, unsigned int sw_index,
+		  unsigned int hw_index, uint32_t toeplitz_hash_result);
+#endif /* __CE_BMI_H__ */
diff --git a/core/hif/src/ce/ce_diag.c b/core/hif/src/ce/ce_diag.c
new file mode 100644
index 0000000..c078f21
--- /dev/null
+++ b/core/hif/src/ce/ce_diag.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#include <osdep.h>
+#include "a_types.h"
+#include "athdefs.h"
+#include "osapi_linux.h"
+#include "targcfg.h"
+#include "cdf_lock.h"
+#include "cdf_status.h"
+#include <cdf_atomic.h>         /* cdf_atomic_read */
+#include <targaddrs.h>
+#include <bmi_msg.h>
+#include "hif_io32.h"
+#include <hif.h>
+#include <htc_services.h>
+#include "regtable.h"
+#include <a_debug.h>
+#include "hif_main.h"
+#include "ce_api.h"
+#include "cdf_trace.h"
+#include "cds_api.h"
+#ifdef CONFIG_CNSS
+#include <net/cnss.h>
+#endif
+#include <cds_get_bin.h>
+#include "hif_debug.h"
+#include "epping_main.h"
+
+void hif_dump_target_memory(struct ol_softc *scn, void *ramdump_base,
+			    uint32_t address, uint32_t size)
+{
+	uint32_t loc = address;
+	uint32_t val = 0;
+	uint32_t j = 0;
+	u8 *temp = ramdump_base;
+
+	A_TARGET_ACCESS_BEGIN(scn);
+	while (j < size) {
+		val = hif_read32_mb(scn->mem + loc + j);
+		cdf_mem_copy(temp, &val, 4);
+		j += 4;
+		temp += 4;
+	}
+	A_TARGET_ACCESS_END(scn);
+}
+/*
+ * TBDXXX: Should be a function call specific to each Target-type.
+ * This convoluted macro converts from Target CPU Virtual Address
+ * Space to CE Address Space. As part of this process, we
+ * conservatively fetch the current PCIE_BAR. MOST of the time,
+ * this should match the upper bits of PCI space for this device;
+ * but that's not guaranteed.
+ */
+#ifdef QCA_WIFI_3_0
+#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \
+	(scn->mem_pa + addr)
+#else
+#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \
+	(((hif_read32_mb((pci_addr) + \
+	(SOC_CORE_BASE_ADDRESS|CORE_CTRL_ADDRESS)) & 0x7ff) << 21) \
+	 | 0x100000 | ((addr) & 0xfffff))
+#endif
+/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
+#define DIAG_ACCESS_CE_TIMEOUT_MS 10
+
+/*
+ * Diagnostic read/write access is provided for startup/config/debug usage.
+ * Caller must guarantee proper alignment, when applicable, and single user
+ * at any moment.
+ */
+
+CDF_STATUS
+hif_diag_read_mem(struct ol_softc *scn, uint32_t address, uint8_t *data,
+		  int nbytes)
+{
+	struct HIF_CE_state *hif_state;
+	CDF_STATUS status = CDF_STATUS_SUCCESS;
+	cdf_dma_addr_t buf;
+	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
+	unsigned int id;
+	unsigned int flags;
+	struct CE_handle *ce_diag;
+	cdf_dma_addr_t CE_data;      /* Host buffer address in CE space */
+	cdf_dma_addr_t CE_data_base = 0;
+	void *data_buf = NULL;
+	int i;
+	unsigned int mux_id = 0;
+	unsigned int transaction_id = 0xffff;
+	cdf_dma_addr_t ce_phy_addr = address;
+	unsigned int toeplitz_hash_result;
+	unsigned int user_flags = 0;
+
+	hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+
+	transaction_id = (mux_id & MUX_ID_MASK) |
+		 (transaction_id & TRANSACTION_ID_MASK);
+#ifdef QCA_WIFI_3_0
+	user_flags &= DESC_DATA_FLAG_MASK;
+#endif
+
+	/* This code cannot handle reads to non-memory space. Redirect to the
+	 * register read fn but preserve the multi word read capability of
+	 * this fn
+	 */
+	if (address < DRAM_BASE_ADDRESS) {
+
+		if ((address & 0x3) || ((uintptr_t) data & 0x3))
+			return CDF_STATUS_E_INVAL;
+
+		while ((nbytes >= 4) &&
+		       (CDF_STATUS_SUCCESS == (status =
+				 hif_diag_read_access(scn, address,
+				       (uint32_t *)data)))) {
+
+			nbytes -= sizeof(uint32_t);
+			address += sizeof(uint32_t);
+			data += sizeof(uint32_t);
+
+		}
+
+		return status;
+	}
+	ce_diag = hif_state->ce_diag;
+
+	A_TARGET_ACCESS_LIKELY(scn);
+
+	/*
+	 * Allocate a temporary bounce buffer to hold caller's data
+	 * to be DMA'ed from Target. This guarantees
+	 *   1) 4-byte alignment
+	 *   2) Buffer in DMA-able space
+	 */
+	orig_nbytes = nbytes;
+	data_buf = cdf_os_mem_alloc_consistent(scn->cdf_dev,
+				    orig_nbytes, &CE_data_base, 0);
+	if (!data_buf) {
+		status = CDF_STATUS_E_NOMEM;
+		goto done;
+	}
+	cdf_mem_set(data_buf, orig_nbytes, 0);
+	cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_data_base,
+				       orig_nbytes, DMA_FROM_DEVICE);
+
+	remaining_bytes = orig_nbytes;
+	CE_data = CE_data_base;
+	while (remaining_bytes) {
+		nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT);
+		{
+			status = ce_recv_buf_enqueue(ce_diag, NULL, CE_data);
+			if (status != CDF_STATUS_SUCCESS)
+				goto done;
+		}
+
+		{	/* Request CE to send from Target(!)
+			 * address to Host buffer */
+			/*
+			 * The address supplied by the caller is in the
+			 * Target CPU virtual address space.
+			 *
+			 * In order to use this address with the diagnostic CE,
+			 * convert it from
+			 *    Target CPU virtual address space
+			 * to
+			 *    CE address space
+			 */
+			A_TARGET_ACCESS_BEGIN_RET(scn);
+			ce_phy_addr =
+				TARG_CPU_SPACE_TO_CE_SPACE(scn->mem, address);
+			A_TARGET_ACCESS_END_RET(scn);
+
+			status =
+				ce_send(ce_diag, NULL, ce_phy_addr, nbytes,
+					transaction_id, 0, user_flags);
+			if (status != CDF_STATUS_SUCCESS)
+				goto done;
+		}
+
+		i = 0;
+		while (ce_completed_send_next(ce_diag, NULL, NULL, &buf,
+				&completed_nbytes, &id, NULL, NULL,
+				&toeplitz_hash_result) != CDF_STATUS_SUCCESS) {
+			cdf_mdelay(1);
+			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+				status = CDF_STATUS_E_BUSY;
+				goto done;
+			}
+		}
+		if (nbytes != completed_nbytes) {
+			status = CDF_STATUS_E_FAILURE;
+			goto done;
+		}
+		if (buf != ce_phy_addr) {
+			status = CDF_STATUS_E_FAILURE;
+			goto done;
+		}
+
+		i = 0;
+		while (ce_completed_recv_next
+				(ce_diag, NULL, NULL, &buf,
+				&completed_nbytes, &id,
+				 &flags) != CDF_STATUS_SUCCESS) {
+			cdf_mdelay(1);
+			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+				status = CDF_STATUS_E_BUSY;
+				goto done;
+			}
+		}
+		if (nbytes != completed_nbytes) {
+			status = CDF_STATUS_E_FAILURE;
+			goto done;
+		}
+		if (buf != CE_data) {
+			status = CDF_STATUS_E_FAILURE;
+			goto done;
+		}
+
+		remaining_bytes -= nbytes;
+		address += nbytes;
+		CE_data += nbytes;
+	}
+
+done:
+	A_TARGET_ACCESS_UNLIKELY(scn);
+
+	if (status == CDF_STATUS_SUCCESS)
+		cdf_mem_copy(data, data_buf, orig_nbytes);
+	else
+		HIF_ERROR("%s failure (0x%x)", __func__, address);
+
+	if (data_buf)
+		cdf_os_mem_free_consistent(scn->cdf_dev, orig_nbytes,
+				    data_buf, CE_data_base, 0);
+
+	return status;
+}
+
+/* Read 4-byte aligned data from Target memory or register */
+CDF_STATUS hif_diag_read_access(struct ol_softc *scn,
+				uint32_t address, uint32_t *data)
+{
+	struct HIF_CE_state *hif_state;
+
+	hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	if (address >= DRAM_BASE_ADDRESS) {
+		/* Assume range doesn't cross this boundary */
+		return hif_diag_read_mem(scn, address, (uint8_t *) data,
+					 sizeof(uint32_t));
+	} else {
+		A_TARGET_ACCESS_BEGIN_RET(scn);
+		*data = A_TARGET_READ(scn, address);
+		A_TARGET_ACCESS_END_RET(scn);
+
+		return CDF_STATUS_SUCCESS;
+	}
+}
+
+CDF_STATUS hif_diag_write_mem(struct ol_softc *scn,
+			      uint32_t address, uint8_t *data, int nbytes)
+{
+	struct HIF_CE_state *hif_state;
+	CDF_STATUS status = CDF_STATUS_SUCCESS;
+	cdf_dma_addr_t buf;
+	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
+	unsigned int id;
+	unsigned int flags;
+	struct CE_handle *ce_diag;
+	void *data_buf = NULL;
+	cdf_dma_addr_t CE_data;      /* Host buffer address in CE space */
+	cdf_dma_addr_t CE_data_base = 0;
+	int i;
+	unsigned int mux_id = 0;
+	unsigned int transaction_id = 0xffff;
+	cdf_dma_addr_t ce_phy_addr = address;
+	unsigned int toeplitz_hash_result;
+	unsigned int user_flags = 0;
+
+	hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	ce_diag = hif_state->ce_diag;
+	transaction_id = (mux_id & MUX_ID_MASK) |
+		(transaction_id & TRANSACTION_ID_MASK);
+#ifdef QCA_WIFI_3_0
+	user_flags &= DESC_DATA_FLAG_MASK;
+#endif
+
+	A_TARGET_ACCESS_LIKELY(scn);
+
+	/*
+	 * Allocate a temporary bounce buffer to hold caller's data
+	 * to be DMA'ed to Target. This guarantees
+	 *   1) 4-byte alignment
+	 *   2) Buffer in DMA-able space
+	 */
+	orig_nbytes = nbytes;
+	data_buf = cdf_os_mem_alloc_consistent(scn->cdf_dev,
+				    orig_nbytes, &CE_data_base, 0);
+	if (!data_buf) {
+		status = A_NO_MEMORY;
+		goto done;
+	}
+
+	/* Copy caller's data to allocated DMA buf */
+	cdf_mem_copy(data_buf, data, orig_nbytes);
+	cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_data_base,
+				       orig_nbytes, DMA_TO_DEVICE);
+
+	/*
+	 * The address supplied by the caller is in the
+	 * Target CPU virtual address space.
+	 *
+	 * In order to use this address with the diagnostic CE,
+	 * convert it from
+	 *    Target CPU virtual address space
+	 * to
+	 *    CE address space
+	 */
+	A_TARGET_ACCESS_BEGIN_RET(scn);
+	ce_phy_addr = TARG_CPU_SPACE_TO_CE_SPACE(scn->mem, address);
+	A_TARGET_ACCESS_END_RET(scn);
+
+	remaining_bytes = orig_nbytes;
+	CE_data = CE_data_base;
+	while (remaining_bytes) {
+		nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT);
+
+		{   /* Set up to receive directly into Target(!) address */
+			status = ce_recv_buf_enqueue(ce_diag,
+						NULL, ce_phy_addr);
+			if (status != CDF_STATUS_SUCCESS)
+				goto done;
+		}
+
+		{
+			/*
+			 * Request CE to send caller-supplied data that
+			 * was copied to bounce buffer to Target(!) address.
+			 */
+			status =
+				ce_send(ce_diag, NULL,
+					(cdf_dma_addr_t) CE_data, nbytes,
+					transaction_id, 0, user_flags);
+			if (status != CDF_STATUS_SUCCESS)
+				goto done;
+		}
+
+		i = 0;
+		while (ce_completed_send_next(ce_diag, NULL, NULL, &buf,
+			    &completed_nbytes, &id,
+			    NULL, NULL, &toeplitz_hash_result) !=
+			    CDF_STATUS_SUCCESS) {
+			cdf_mdelay(1);
+			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+				status = CDF_STATUS_E_BUSY;
+				goto done;
+			}
+		}
+
+		if (nbytes != completed_nbytes) {
+			status = CDF_STATUS_E_FAILURE;
+			goto done;
+		}
+
+		if (buf != CE_data) {
+			status = CDF_STATUS_E_FAILURE;
+			goto done;
+		}
+
+		i = 0;
+		while (ce_completed_recv_next
+			(ce_diag, NULL, NULL, &buf,
+			&completed_nbytes, &id,
+			&flags) != CDF_STATUS_SUCCESS) {
+			cdf_mdelay(1);
+			if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+				status = CDF_STATUS_E_BUSY;
+				goto done;
+			}
+		}
+
+		if (nbytes != completed_nbytes) {
+			status = CDF_STATUS_E_FAILURE;
+			goto done;
+		}
+
+		if (buf != ce_phy_addr) {
+			status = CDF_STATUS_E_FAILURE;
+			goto done;
+		}
+
+		remaining_bytes -= nbytes;
+		address += nbytes;
+		CE_data += nbytes;
+	}
+
+done:
+	A_TARGET_ACCESS_UNLIKELY(scn);
+
+	if (data_buf) {
+		cdf_os_mem_free_consistent(scn->cdf_dev, orig_nbytes,
+				    data_buf, CE_data_base, 0);
+	}
+
+	if (status != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s failure (0x%llu)", __func__,
+			(uint64_t)ce_phy_addr);
+	}
+
+	return status;
+}
+
+/* Write 4B data to Target memory or register */
+CDF_STATUS
+hif_diag_write_access(struct ol_softc *scn, uint32_t address, uint32_t data)
+{
+	struct HIF_CE_state *hif_state;
+
+	hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	if (address >= DRAM_BASE_ADDRESS) {
+		/* Assume range doesn't cross this boundary */
+		uint32_t data_buf = data;
+
+		return hif_diag_write_mem(scn, address,
+					  (uint8_t *) &data_buf,
+					  sizeof(uint32_t));
+	} else {
+		A_TARGET_ACCESS_BEGIN_RET(scn);
+		A_TARGET_WRITE(scn, address, data);
+		A_TARGET_ACCESS_END_RET(scn);
+
+		return CDF_STATUS_SUCCESS;
+	}
+}
diff --git a/core/hif/src/ce/ce_internal.h b/core/hif/src/ce/ce_internal.h
new file mode 100644
index 0000000..b3fa707
--- /dev/null
+++ b/core/hif/src/ce/ce_internal.h
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+#ifndef __COPY_ENGINE_INTERNAL_H__
+#define __COPY_ENGINE_INTERNAL_H__
+
+#include <hif.h>                /* A_TARGET_WRITE */
+
+/* Copy Engine operational state */
+enum CE_op_state {
+	CE_UNUSED,
+	CE_PAUSED,
+	CE_RUNNING,
+};
+
+enum ol_ath_hif_ce_ecodes {
+	CE_RING_DELTA_FAIL = 0
+};
+
+struct CE_src_desc;
+
+/* Copy Engine Ring internal state */
+struct CE_ring_state {
+
+	/* Number of entries in this ring; must be power of 2 */
+	unsigned int nentries;
+	unsigned int nentries_mask;
+
+	/*
+	 * For dest ring, this is the next index to be processed
+	 * by software after it was/is received into.
+	 *
+	 * For src ring, this is the last descriptor that was sent
+	 * and completion processed by software.
+	 *
+	 * Regardless of src or dest ring, this is an invariant
+	 * (modulo ring size):
+	 *     write index >= read index >= sw_index
+	 */
+	unsigned int sw_index;
+	unsigned int write_index;       /* cached copy */
+	/*
+	 * For src ring, this is the next index not yet processed by HW.
+	 * This is a cached copy of the real HW index (read index), used
+	 * for avoiding reading the HW index register more often than
+	 * necessary.
+	 * This extends the invariant:
+	 *     write index >= read index >= hw_index >= sw_index
+	 *
+	 * For dest ring, this is currently unused.
+	 */
+	unsigned int hw_index;  /* cached copy */
+
+	/* Start of DMA-coherent area reserved for descriptors */
+	void *base_addr_owner_space_unaligned;  /* Host address space */
+	cdf_dma_addr_t base_addr_CE_space_unaligned; /* CE address space */
+
+	/*
+	 * Actual start of descriptors.
+	 * Aligned to descriptor-size boundary.
+	 * Points into reserved DMA-coherent area, above.
+	 */
+	void *base_addr_owner_space;    /* Host address space */
+	cdf_dma_addr_t base_addr_CE_space;   /* CE address space */
+	/*
+	 * Start of shadow copy of descriptors, within regular memory.
+	 * Aligned to descriptor-size boundary.
+	 */
+	char *shadow_base_unaligned;
+	struct CE_src_desc *shadow_base;
+
+	unsigned int low_water_mark_nentries;
+	unsigned int high_water_mark_nentries;
+	void **per_transfer_context;
+	OS_DMA_MEM_CONTEXT(ce_dmacontext) /* OS Specific DMA context */
+};
+
+/* Copy Engine internal state */
+struct CE_state {
+	struct ol_softc *scn;
+	unsigned int id;
+	unsigned int attr_flags;  /* CE_ATTR_* */
+	uint32_t ctrl_addr;       /* relative to BAR */
+	enum CE_op_state state;
+
+#ifdef WLAN_FEATURE_FASTPATH
+	u_int32_t download_len; /* pkt download length for source ring */
+#endif /* WLAN_FEATURE_FASTPATH */
+
+	ce_send_cb send_cb;
+	void *send_context;
+
+	CE_recv_cb recv_cb;
+	void *recv_context;
+
+	/* misc_cbs - are any callbacks besides send and recv enabled? */
+	uint8_t misc_cbs;
+
+	CE_watermark_cb watermark_cb;
+	void *wm_context;
+
+	/*Record the state of the copy compl interrupt */
+	int disable_copy_compl_intr;
+
+	unsigned int src_sz_max;
+	struct CE_ring_state *src_ring;
+	struct CE_ring_state *dest_ring;
+	atomic_t rx_pending;
+
+	/* epping */
+	bool timer_inited;
+	cdf_softirq_timer_t poll_timer;
+	void (*lro_flush_cb)(void *);
+	void *lro_data;
+};
+
+/* Descriptor rings must be aligned to this boundary */
+#define CE_DESC_RING_ALIGN 8
+
+#ifdef QCA_WIFI_3_0
+#define HIF_CE_DESC_ADDR_TO_DMA(desc) \
+	(cdf_dma_addr_t)(((uint64_t)(desc)->buffer_addr + \
+	((uint64_t)((desc)->buffer_addr_hi & 0x1F) << 32)))
+#else
+#define HIF_CE_DESC_ADDR_TO_DMA(desc) \
+	(cdf_dma_addr_t)((desc)->buffer_addr)
+#endif
+
+#ifdef QCA_WIFI_3_0
+struct CE_src_desc {
+	uint32_t buffer_addr:32;
+#if _BYTE_ORDER == _BIG_ENDIAN
+	uint32_t gather:1,
+		enable_11h:1,
+		meta_data_low:2, /* fw_metadata_low */
+		packet_result_offset:12,
+		toeplitz_hash_enable:1,
+		addr_y_search_disable:1,
+		addr_x_search_disable:1,
+		misc_int_disable:1,
+		target_int_disable:1,
+		host_int_disable:1,
+		dest_byte_swap:1,
+		byte_swap:1,
+		type:2,
+		tx_classify:1,
+		buffer_addr_hi:5;
+		uint32_t meta_data:16, /* fw_metadata_high */
+		nbytes:16;       /* length in register map */
+#else
+	uint32_t buffer_addr_hi:5,
+		tx_classify:1,
+		type:2,
+		byte_swap:1,          /* src_byte_swap */
+		dest_byte_swap:1,
+		host_int_disable:1,
+		target_int_disable:1,
+		misc_int_disable:1,
+		addr_x_search_disable:1,
+		addr_y_search_disable:1,
+		toeplitz_hash_enable:1,
+		packet_result_offset:12,
+		meta_data_low:2, /* fw_metadata_low */
+		enable_11h:1,
+		gather:1;
+		uint32_t nbytes:16, /* length in register map */
+		meta_data:16; /* fw_metadata_high */
+#endif
+	uint32_t toeplitz_hash_result:32;
+};
+
+struct CE_dest_desc {
+	uint32_t buffer_addr:32;
+#if _BYTE_ORDER == _BIG_ENDIAN
+	uint32_t gather:1,
+		enable_11h:1,
+		meta_data_low:2, /* fw_metadata_low */
+		packet_result_offset:12,
+		toeplitz_hash_enable:1,
+		addr_y_search_disable:1,
+		addr_x_search_disable:1,
+		misc_int_disable:1,
+		target_int_disable:1,
+		host_int_disable:1,
+		byte_swap:1,
+		src_byte_swap:1,
+		type:2,
+		tx_classify:1,
+		buffer_addr_hi:5;
+		uint32_t meta_data:16, /* fw_metadata_high */
+		nbytes:16;          /* length in register map */
+#else
+	uint32_t buffer_addr_hi:5,
+		tx_classify:1,
+		type:2,
+		src_byte_swap:1,
+		byte_swap:1,         /* dest_byte_swap */
+		host_int_disable:1,
+		target_int_disable:1,
+		misc_int_disable:1,
+		addr_x_search_disable:1,
+		addr_y_search_disable:1,
+		toeplitz_hash_enable:1,
+		packet_result_offset:12,
+		meta_data_low:2, /* fw_metadata_low */
+		enable_11h:1,
+		gather:1;
+		uint32_t nbytes:16, /* length in register map */
+		meta_data:16;    /* fw_metadata_high */
+#endif
+	uint32_t toeplitz_hash_result:32;
+};
+#else
+struct CE_src_desc {
+	uint32_t buffer_addr;
+#if _BYTE_ORDER == _BIG_ENDIAN
+	uint32_t  meta_data:14,
+		byte_swap:1,
+		gather:1,
+		nbytes:16;
+#else
+
+		uint32_t nbytes:16,
+		gather:1,
+		byte_swap:1,
+		meta_data:14;
+#endif
+};
+
+struct CE_dest_desc {
+	uint32_t buffer_addr;
+#if _BYTE_ORDER == _BIG_ENDIAN
+	uint32_t  meta_data:14,
+		byte_swap:1,
+		gather:1,
+		nbytes:16;
+#else
+	uint32_t nbytes:16,
+		gather:1,
+		byte_swap:1,
+		meta_data:14;
+#endif
+};
+#endif /* QCA_WIFI_3_0 */
+
+#define CE_SENDLIST_ITEMS_MAX 12
+
+enum ce_sendlist_type_e {
+	CE_SIMPLE_BUFFER_TYPE,
+	/* TBDXXX: CE_RX_DESC_LIST, */
+};
+
+/*
+ * There's a public "ce_sendlist" and a private "ce_sendlist_s".
+ * The former is an opaque structure with sufficient space
+ * to hold the latter.  The latter is the actual structure
+ * definition and it is only used internally.  The opaque version
+ * of the structure allows callers to allocate an instance on the
+ * run-time stack without knowing any of the details of the
+ * structure layout.
+ */
+struct ce_sendlist_s {
+	unsigned int num_items;
+	struct ce_sendlist_item {
+		enum ce_sendlist_type_e send_type;
+		dma_addr_t data;        /* e.g. buffer or desc list */
+		union {
+			unsigned int nbytes;    /* simple buffer */
+			unsigned int ndesc;     /* Rx descriptor list */
+		} u;
+		/* flags: externally-specified flags;
+		 * OR-ed with internal flags */
+		uint32_t flags;
+		uint32_t user_flags;
+	} item[CE_SENDLIST_ITEMS_MAX];
+};
+
+#ifdef WLAN_FEATURE_FASTPATH
+void ce_h2t_tx_ce_cleanup(struct CE_handle *ce_hdl);
+#endif
+
+/* which ring of a CE? */
+#define CE_RING_SRC  0
+#define CE_RING_DEST 1
+
+#define CDC_WAR_MAGIC_STR   0xceef0000
+#define CDC_WAR_DATA_CE     4
+
+/* Additional internal-only ce_send flags */
+#define CE_SEND_FLAG_GATHER             0x00010000      /* Use Gather */
+#endif /* __COPY_ENGINE_INTERNAL_H__ */
diff --git a/core/hif/src/ce/ce_main.c b/core/hif/src/ce/ce_main.c
new file mode 100644
index 0000000..8cf00f1
--- /dev/null
+++ b/core/hif/src/ce/ce_main.c
@@ -0,0 +1,2593 @@
+/*
+ * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+#include <osdep.h>
+#include "a_types.h"
+#include "athdefs.h"
+#include "osapi_linux.h"
+#include "targcfg.h"
+#include "cdf_lock.h"
+#include "cdf_status.h"
+#include <cdf_atomic.h>         /* cdf_atomic_read */
+#include <targaddrs.h>
+#include <bmi_msg.h>
+#include "hif_io32.h"
+#include <hif.h>
+#include "regtable.h"
+#define ATH_MODULE_NAME hif
+#include <a_debug.h>
+#include "hif_main.h"
+#ifdef HIF_PCI
+#include "ce_bmi.h"
+#endif
+#include "ce_api.h"
+#include "cdf_trace.h"
+#include "cds_api.h"
+#ifdef CONFIG_CNSS
+#include <net/cnss.h>
+#endif
+#include <cds_get_bin.h>
+#include "epping_main.h"
+#include "hif_debug.h"
+#include "ce_internal.h"
+#include "ce_reg.h"
+#include "ce_assignment.h"
+#include "ce_tasklet.h"
+#ifdef HIF_PCI
+#include "icnss_stub.h"
+#else
+#include <soc/qcom/icnss.h>
+#endif
+#include "qwlan_version.h"
+
+#define CE_POLL_TIMEOUT 10      /* ms */
+
+/* Forward references */
+static int hif_post_recv_buffers_for_pipe(struct HIF_CE_pipe_info *pipe_info);
+
+/*
+ * Fix EV118783, poll to check whether a BMI response comes
+ * other than waiting for the interruption which may be lost.
+ */
+/* #define BMI_RSP_POLLING */
+#define BMI_RSP_TO_MILLISEC  1000
+
+
+static int hif_post_recv_buffers(struct ol_softc *scn);
+
+static void ce_poll_timeout(void *arg)
+{
+	struct CE_state *CE_state = (struct CE_state *)arg;
+	if (CE_state->timer_inited) {
+		ce_per_engine_service(CE_state->scn, CE_state->id);
+		cdf_softirq_timer_mod(&CE_state->poll_timer, CE_POLL_TIMEOUT);
+	}
+}
+
+static unsigned int roundup_pwr2(unsigned int n)
+{
+	int i;
+	unsigned int test_pwr2;
+
+	if (!(n & (n - 1)))
+		return n; /* already a power of 2 */
+
+	test_pwr2 = 4;
+	for (i = 0; i < 29; i++) {
+		if (test_pwr2 > n)
+			return test_pwr2;
+		test_pwr2 = test_pwr2 << 1;
+	}
+
+	CDF_ASSERT(0); /* n too large */
+	return 0;
+}
+
+/*
+ * Initialize a Copy Engine based on caller-supplied attributes.
+ * This may be called once to initialize both source and destination
+ * rings or it may be called twice for separate source and destination
+ * initialization. It may be that only one side or the other is
+ * initialized by software/firmware.
+ */
+struct CE_handle *ce_init(struct ol_softc *scn,
+			  unsigned int CE_id, struct CE_attr *attr)
+{
+	struct CE_state *CE_state;
+	uint32_t ctrl_addr;
+	unsigned int nentries;
+	cdf_dma_addr_t base_addr;
+	bool malloc_CE_state = false;
+	bool malloc_src_ring = false;
+
+	CDF_ASSERT(CE_id < scn->ce_count);
+	ctrl_addr = CE_BASE_ADDRESS(CE_id);
+	cdf_spin_lock(&scn->target_lock);
+	CE_state = scn->ce_id_to_state[CE_id];
+
+	if (!CE_state) {
+		cdf_spin_unlock(&scn->target_lock);
+		CE_state =
+		    (struct CE_state *)cdf_mem_malloc(sizeof(*CE_state));
+		if (!CE_state) {
+			HIF_ERROR("%s: CE_state has no mem", __func__);
+			return NULL;
+		} else
+			malloc_CE_state = true;
+		cdf_mem_zero(CE_state, sizeof(*CE_state));
+		cdf_spin_lock(&scn->target_lock);
+		if (!scn->ce_id_to_state[CE_id]) { /* re-check under lock */
+			scn->ce_id_to_state[CE_id] = CE_state;
+
+			CE_state->id = CE_id;
+			CE_state->ctrl_addr = ctrl_addr;
+			CE_state->state = CE_RUNNING;
+			CE_state->attr_flags = attr->flags;
+		} else {
+			/*
+			 * We released target_lock in order to allocate
+			 * CE state, but someone else beat us to it.
+			 * Continue, using that CE_state
+			 * (and free the one we allocated).
+			 */
+			cdf_mem_free(CE_state);
+			malloc_CE_state = false;
+			CE_state = scn->ce_id_to_state[CE_id];
+		}
+	}
+	CE_state->scn = scn;
+	cdf_spin_unlock(&scn->target_lock);
+
+	cdf_atomic_init(&CE_state->rx_pending);
+	if (attr == NULL) {
+		/* Already initialized; caller wants the handle */
+		return (struct CE_handle *)CE_state;
+	}
+
+#ifdef ADRASTEA_SHADOW_REGISTERS
+	HIF_ERROR("%s: Using Shadow Registers instead of CE Registers\n",
+		  __func__);
+#endif
+
+	if (CE_state->src_sz_max)
+		CDF_ASSERT(CE_state->src_sz_max == attr->src_sz_max);
+	else
+		CE_state->src_sz_max = attr->src_sz_max;
+
+	/* source ring setup */
+	nentries = attr->src_nentries;
+	if (nentries) {
+		struct CE_ring_state *src_ring;
+		unsigned CE_nbytes;
+		char *ptr;
+		uint64_t dma_addr;
+		nentries = roundup_pwr2(nentries);
+		if (CE_state->src_ring) {
+			CDF_ASSERT(CE_state->src_ring->nentries == nentries);
+		} else {
+			CE_nbytes = sizeof(struct CE_ring_state)
+				    + (nentries * sizeof(void *));
+			ptr = cdf_mem_malloc(CE_nbytes);
+			if (!ptr) {
+				/* cannot allocate src ring. If the
+				 * CE_state is allocated locally free
+				 * CE_State and return error.
+				 */
+				HIF_ERROR("%s: src ring has no mem", __func__);
+				if (malloc_CE_state) {
+					/* allocated CE_state locally */
+					cdf_spin_lock(&scn->target_lock);
+					scn->ce_id_to_state[CE_id] = NULL;
+					cdf_spin_unlock(&scn->target_lock);
+					cdf_mem_free(CE_state);
+					malloc_CE_state = false;
+				}
+				return NULL;
+			} else {
+				/* we can allocate src ring.
+				 * Mark that the src ring is
+				 * allocated locally
+				 */
+				malloc_src_ring = true;
+			}
+			cdf_mem_zero(ptr, CE_nbytes);
+
+			src_ring = CE_state->src_ring =
+					   (struct CE_ring_state *)ptr;
+			ptr += sizeof(struct CE_ring_state);
+			src_ring->nentries = nentries;
+			src_ring->nentries_mask = nentries - 1;
+			A_TARGET_ACCESS_BEGIN_RET_PTR(scn);
+			src_ring->hw_index =
+				CE_SRC_RING_READ_IDX_GET(scn, ctrl_addr);
+			src_ring->sw_index = src_ring->hw_index;
+			src_ring->write_index =
+				CE_SRC_RING_WRITE_IDX_GET(scn, ctrl_addr);
+			A_TARGET_ACCESS_END_RET_PTR(scn);
+			src_ring->low_water_mark_nentries = 0;
+			src_ring->high_water_mark_nentries = nentries;
+			src_ring->per_transfer_context = (void **)ptr;
+
+			/* Legacy platforms that do not support cache
+			 * coherent DMA are unsupported
+			 */
+			src_ring->base_addr_owner_space_unaligned =
+				cdf_os_mem_alloc_consistent(scn->cdf_dev,
+						(nentries *
+						sizeof(struct CE_src_desc) +
+						CE_DESC_RING_ALIGN),
+						&base_addr, 0);
+			if (src_ring->base_addr_owner_space_unaligned
+					== NULL) {
+				HIF_ERROR("%s: src ring has no DMA mem",
+					  __func__);
+				goto error_no_dma_mem;
+			}
+			src_ring->base_addr_CE_space_unaligned = base_addr;
+
+			if (src_ring->
+			    base_addr_CE_space_unaligned & (CE_DESC_RING_ALIGN
+							- 1)) {
+				src_ring->base_addr_CE_space =
+					(src_ring->base_addr_CE_space_unaligned
+					+ CE_DESC_RING_ALIGN -
+					 1) & ~(CE_DESC_RING_ALIGN - 1);
+
+				src_ring->base_addr_owner_space =
+					(void
+					 *)(((size_t) src_ring->
+					     base_addr_owner_space_unaligned +
+					     CE_DESC_RING_ALIGN -
+					     1) & ~(CE_DESC_RING_ALIGN - 1));
+			} else {
+				src_ring->base_addr_CE_space =
+					src_ring->base_addr_CE_space_unaligned;
+				src_ring->base_addr_owner_space =
+					src_ring->
+					base_addr_owner_space_unaligned;
+			}
+			/*
+			 * Also allocate a shadow src ring in
+			 * regular mem to use for faster access.
+			 */
+			src_ring->shadow_base_unaligned =
+				cdf_mem_malloc(nentries *
+					       sizeof(struct CE_src_desc) +
+					       CE_DESC_RING_ALIGN);
+			if (src_ring->shadow_base_unaligned == NULL) {
+				HIF_ERROR("%s: src ring no shadow_base mem",
+					  __func__);
+				goto error_no_dma_mem;
+			}
+			src_ring->shadow_base = (struct CE_src_desc *)
+				(((size_t) src_ring->shadow_base_unaligned +
+				CE_DESC_RING_ALIGN - 1) &
+				 ~(CE_DESC_RING_ALIGN - 1));
+
+			A_TARGET_ACCESS_BEGIN_RET_PTR(scn);
+			dma_addr = src_ring->base_addr_CE_space;
+			CE_SRC_RING_BASE_ADDR_SET(scn, ctrl_addr,
+				 (uint32_t)(dma_addr & 0xFFFFFFFF));
+#ifdef WLAN_ENABLE_QCA6180
+			{
+				uint32_t tmp;
+				tmp = CE_SRC_RING_BASE_ADDR_HIGH_GET(
+				   scn, ctrl_addr);
+				tmp &= ~0x1F;
+				dma_addr = ((dma_addr >> 32) & 0x1F)|tmp;
+				CE_SRC_RING_BASE_ADDR_HIGH_SET(scn,
+					 ctrl_addr, (uint32_t)dma_addr);
+			}
+#endif
+			CE_SRC_RING_SZ_SET(scn, ctrl_addr, nentries);
+			CE_SRC_RING_DMAX_SET(scn, ctrl_addr, attr->src_sz_max);
+#ifdef BIG_ENDIAN_HOST
+			/* Enable source ring byte swap for big endian host */
+			CE_SRC_RING_BYTE_SWAP_SET(scn, ctrl_addr, 1);
+#endif
+			CE_SRC_RING_LOWMARK_SET(scn, ctrl_addr, 0);
+			CE_SRC_RING_HIGHMARK_SET(scn, ctrl_addr, nentries);
+			A_TARGET_ACCESS_END_RET_PTR(scn);
+		}
+	}
+
+	/* destination ring setup */
+	nentries = attr->dest_nentries;
+	if (nentries) {
+		struct CE_ring_state *dest_ring;
+		unsigned CE_nbytes;
+		char *ptr;
+		uint64_t dma_addr;
+
+		nentries = roundup_pwr2(nentries);
+		if (CE_state->dest_ring) {
+			CDF_ASSERT(CE_state->dest_ring->nentries == nentries);
+		} else {
+			CE_nbytes = sizeof(struct CE_ring_state)
+				    + (nentries * sizeof(void *));
+			ptr = cdf_mem_malloc(CE_nbytes);
+			if (!ptr) {
+				/* cannot allocate dst ring. If the CE_state
+				 * or src ring is allocated locally free
+				 * CE_State and src ring and return error.
+				 */
+				HIF_ERROR("%s: dest ring has no mem",
+					  __func__);
+				if (malloc_src_ring) {
+					cdf_mem_free(CE_state->src_ring);
+					CE_state->src_ring = NULL;
+					malloc_src_ring = false;
+				}
+				if (malloc_CE_state) {
+					/* allocated CE_state locally */
+					cdf_spin_lock(&scn->target_lock);
+					scn->ce_id_to_state[CE_id] = NULL;
+					cdf_spin_unlock(&scn->target_lock);
+					cdf_mem_free(CE_state);
+					malloc_CE_state = false;
+				}
+				return NULL;
+			}
+			cdf_mem_zero(ptr, CE_nbytes);
+
+			dest_ring = CE_state->dest_ring =
+					    (struct CE_ring_state *)ptr;
+			ptr += sizeof(struct CE_ring_state);
+			dest_ring->nentries = nentries;
+			dest_ring->nentries_mask = nentries - 1;
+			A_TARGET_ACCESS_BEGIN_RET_PTR(scn);
+			dest_ring->sw_index =
+				CE_DEST_RING_READ_IDX_GET(scn, ctrl_addr);
+			dest_ring->write_index =
+				CE_DEST_RING_WRITE_IDX_GET(scn, ctrl_addr);
+			A_TARGET_ACCESS_END_RET_PTR(scn);
+			dest_ring->low_water_mark_nentries = 0;
+			dest_ring->high_water_mark_nentries = nentries;
+			dest_ring->per_transfer_context = (void **)ptr;
+
+			/* Legacy platforms that do not support cache
+			 * coherent DMA are unsupported */
+			dest_ring->base_addr_owner_space_unaligned =
+				cdf_os_mem_alloc_consistent(scn->cdf_dev,
+						(nentries *
+						sizeof(struct CE_dest_desc) +
+						CE_DESC_RING_ALIGN),
+						&base_addr, 0);
+			if (dest_ring->base_addr_owner_space_unaligned
+				== NULL) {
+				HIF_ERROR("%s: dest ring has no DMA mem",
+					  __func__);
+				goto error_no_dma_mem;
+			}
+			dest_ring->base_addr_CE_space_unaligned = base_addr;
+
+			/* Correctly initialize memory to 0 to
+			 * prevent garbage data crashing system
+			 * when download firmware
+			 */
+			cdf_mem_zero(dest_ring->base_addr_owner_space_unaligned,
+				  nentries * sizeof(struct CE_dest_desc) +
+				  CE_DESC_RING_ALIGN);
+
+			if (dest_ring->
+			    base_addr_CE_space_unaligned & (CE_DESC_RING_ALIGN -
+							    1)) {
+
+				dest_ring->base_addr_CE_space =
+					(dest_ring->
+					 base_addr_CE_space_unaligned +
+					 CE_DESC_RING_ALIGN -
+					 1) & ~(CE_DESC_RING_ALIGN - 1);
+
+				dest_ring->base_addr_owner_space =
+					(void
+					 *)(((size_t) dest_ring->
+					     base_addr_owner_space_unaligned +
+					     CE_DESC_RING_ALIGN -
+					     1) & ~(CE_DESC_RING_ALIGN - 1));
+			} else {
+				dest_ring->base_addr_CE_space =
+					dest_ring->base_addr_CE_space_unaligned;
+				dest_ring->base_addr_owner_space =
+					dest_ring->
+					base_addr_owner_space_unaligned;
+			}
+
+			A_TARGET_ACCESS_BEGIN_RET_PTR(scn);
+			dma_addr = dest_ring->base_addr_CE_space;
+			CE_DEST_RING_BASE_ADDR_SET(scn, ctrl_addr,
+				 (uint32_t)(dma_addr & 0xFFFFFFFF));
+#ifdef WLAN_ENABLE_QCA6180
+			{
+				uint32_t tmp;
+				tmp = CE_DEST_RING_BASE_ADDR_HIGH_GET(scn,
+						ctrl_addr);
+				tmp &= ~0x1F;
+				dma_addr = ((dma_addr >> 32) & 0x1F)|tmp;
+				CE_DEST_RING_BASE_ADDR_HIGH_SET(scn,
+					ctrl_addr, (uint32_t)dma_addr);
+			}
+#endif
+			CE_DEST_RING_SZ_SET(scn, ctrl_addr, nentries);
+#ifdef BIG_ENDIAN_HOST
+			/* Enable Dest ring byte swap for big endian host */
+			CE_DEST_RING_BYTE_SWAP_SET(scn, ctrl_addr, 1);
+#endif
+			CE_DEST_RING_LOWMARK_SET(scn, ctrl_addr, 0);
+			CE_DEST_RING_HIGHMARK_SET(scn, ctrl_addr, nentries);
+			A_TARGET_ACCESS_END_RET_PTR(scn);
+
+			/* epping */
+			/* poll timer */
+			if ((CE_state->attr_flags & CE_ATTR_ENABLE_POLL)) {
+				cdf_softirq_timer_init(scn->cdf_dev,
+						       &CE_state->poll_timer,
+						       ce_poll_timeout,
+						       CE_state,
+						       CDF_TIMER_TYPE_SW);
+				CE_state->timer_inited = true;
+				cdf_softirq_timer_mod(&CE_state->poll_timer,
+						      CE_POLL_TIMEOUT);
+			}
+		}
+	}
+
+	/* Enable CE error interrupts */
+	A_TARGET_ACCESS_BEGIN_RET_PTR(scn);
+	CE_ERROR_INTR_ENABLE(scn, ctrl_addr);
+	A_TARGET_ACCESS_END_RET_PTR(scn);
+
+	return (struct CE_handle *)CE_state;
+
+error_no_dma_mem:
+	ce_fini((struct CE_handle *)CE_state);
+	return NULL;
+}
+
+#ifdef WLAN_FEATURE_FASTPATH
+/**
+ * ce_h2t_tx_ce_cleanup() Place holder function for H2T CE cleanup.
+ * No processing is required inside this function.
+ * @ce_hdl: Cope engine handle
+ * Using an assert, this function makes sure that,
+ * the TX CE has been processed completely.
+ * Return: none
+ */
+void
+ce_h2t_tx_ce_cleanup(struct CE_handle *ce_hdl)
+{
+	struct CE_state *ce_state = (struct CE_state *)ce_hdl;
+	struct CE_ring_state *src_ring = ce_state->src_ring;
+	struct ol_softc *sc = ce_state->scn;
+	uint32_t sw_index, write_index;
+
+	if (sc->fastpath_mode_on && (ce_state->id == CE_HTT_H2T_MSG)) {
+		HIF_INFO("%s %d Fastpath mode ON, Cleaning up HTT Tx CE\n",
+			  __func__, __LINE__);
+		cdf_spin_lock_bh(&sc->target_lock);
+		sw_index = src_ring->sw_index;
+		write_index = src_ring->sw_index;
+		cdf_spin_unlock_bh(&sc->target_lock);
+
+		/* At this point Tx CE should be clean */
+		cdf_assert_always(sw_index == write_index);
+	}
+}
+#else
+void ce_h2t_tx_ce_cleanup(struct CE_handle *ce_hdl)
+{
+}
+#endif /* WLAN_FEATURE_FASTPATH */
+
+void ce_fini(struct CE_handle *copyeng)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	unsigned int CE_id = CE_state->id;
+	struct ol_softc *scn = CE_state->scn;
+
+	CE_state->state = CE_UNUSED;
+	scn->ce_id_to_state[CE_id] = NULL;
+	if (CE_state->src_ring) {
+		/* Cleanup the HTT Tx ring */
+		ce_h2t_tx_ce_cleanup(copyeng);
+
+		if (CE_state->src_ring->shadow_base_unaligned)
+			cdf_mem_free(CE_state->src_ring->shadow_base_unaligned);
+		if (CE_state->src_ring->base_addr_owner_space_unaligned)
+			cdf_os_mem_free_consistent(scn->cdf_dev,
+					    (CE_state->src_ring->nentries *
+					     sizeof(struct CE_src_desc) +
+					     CE_DESC_RING_ALIGN),
+					    CE_state->src_ring->
+					    base_addr_owner_space_unaligned,
+					    CE_state->src_ring->
+					    base_addr_CE_space, 0);
+		cdf_mem_free(CE_state->src_ring);
+	}
+	if (CE_state->dest_ring) {
+		if (CE_state->dest_ring->base_addr_owner_space_unaligned)
+			cdf_os_mem_free_consistent(scn->cdf_dev,
+					    (CE_state->dest_ring->nentries *
+					     sizeof(struct CE_dest_desc) +
+					     CE_DESC_RING_ALIGN),
+					    CE_state->dest_ring->
+					    base_addr_owner_space_unaligned,
+					    CE_state->dest_ring->
+					    base_addr_CE_space, 0);
+		cdf_mem_free(CE_state->dest_ring);
+
+		/* epping */
+		if (CE_state->timer_inited) {
+			CE_state->timer_inited = false;
+			cdf_softirq_timer_free(&CE_state->poll_timer);
+		}
+	}
+	cdf_mem_free(CE_state);
+}
+
+void hif_detach_htc(struct ol_softc *scn)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+
+	cdf_mem_zero(&hif_state->msg_callbacks_pending,
+		  sizeof(hif_state->msg_callbacks_pending));
+	cdf_mem_zero(&hif_state->msg_callbacks_current,
+		  sizeof(hif_state->msg_callbacks_current));
+}
+
+/* Send the first nbytes bytes of the buffer */
+CDF_STATUS
+hif_send_head(struct ol_softc *scn,
+	      uint8_t pipe, unsigned int transfer_id, unsigned int nbytes,
+	      cdf_nbuf_t nbuf, unsigned int data_attr)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	struct HIF_CE_pipe_info *pipe_info = &(hif_state->pipe_info[pipe]);
+	struct CE_handle *ce_hdl = pipe_info->ce_hdl;
+	int bytes = nbytes, nfrags = 0;
+	struct ce_sendlist sendlist;
+	int status, i = 0;
+	unsigned int mux_id = 0;
+
+	CDF_ASSERT(nbytes <= cdf_nbuf_len(nbuf));
+
+	transfer_id =
+		(mux_id & MUX_ID_MASK) |
+		(transfer_id & TRANSACTION_ID_MASK);
+	data_attr &= DESC_DATA_FLAG_MASK;
+	/*
+	 * The common case involves sending multiple fragments within a
+	 * single download (the tx descriptor and the tx frame header).
+	 * So, optimize for the case of multiple fragments by not even
+	 * checking whether it's necessary to use a sendlist.
+	 * The overhead of using a sendlist for a single buffer download
+	 * is not a big deal, since it happens rarely (for WMI messages).
+	 */
+	ce_sendlist_init(&sendlist);
+	do {
+		uint32_t frag_paddr;
+		int frag_bytes;
+
+		frag_paddr = cdf_nbuf_get_frag_paddr_lo(nbuf, nfrags);
+		frag_bytes = cdf_nbuf_get_frag_len(nbuf, nfrags);
+		/*
+		 * Clear the packet offset for all but the first CE desc.
+		 */
+		if (i++ > 0)
+			data_attr &= ~CDF_CE_TX_PKT_OFFSET_BIT_M;
+
+		status = ce_sendlist_buf_add(&sendlist, frag_paddr,
+				    frag_bytes >
+				    bytes ? bytes : frag_bytes,
+				    cdf_nbuf_get_frag_is_wordstream
+				    (nbuf,
+				    nfrags) ? 0 :
+				    CE_SEND_FLAG_SWAP_DISABLE,
+				    data_attr);
+		if (status != CDF_STATUS_SUCCESS) {
+			HIF_ERROR("%s: error, frag_num %d larger than limit",
+				__func__, nfrags);
+			return status;
+		}
+		bytes -= frag_bytes;
+		nfrags++;
+	} while (bytes > 0);
+
+	/* Make sure we have resources to handle this request */
+	cdf_spin_lock_bh(&pipe_info->completion_freeq_lock);
+	if (pipe_info->num_sends_allowed < nfrags) {
+		cdf_spin_unlock_bh(&pipe_info->completion_freeq_lock);
+		ce_pkt_error_count_incr(hif_state, HIF_PIPE_NO_RESOURCE);
+		return CDF_STATUS_E_RESOURCES;
+	}
+	pipe_info->num_sends_allowed -= nfrags;
+	cdf_spin_unlock_bh(&pipe_info->completion_freeq_lock);
+
+	if (cdf_unlikely(ce_hdl == NULL)) {
+		HIF_ERROR("%s: error CE handle is null", __func__);
+		return A_ERROR;
+	}
+
+	NBUF_UPDATE_TX_PKT_COUNT(nbuf, NBUF_TX_PKT_HIF);
+	DPTRACE(cdf_dp_trace(nbuf, CDF_DP_TRACE_HIF_PACKET_PTR_RECORD,
+				(uint8_t *)(cdf_nbuf_data(nbuf)),
+				sizeof(cdf_nbuf_data(nbuf))));
+	status = ce_sendlist_send(ce_hdl, nbuf, &sendlist, transfer_id);
+	CDF_ASSERT(status == CDF_STATUS_SUCCESS);
+
+	return status;
+}
+
+void hif_send_complete_check(struct ol_softc *scn, uint8_t pipe, int force)
+{
+	if (!force) {
+		int resources;
+		/*
+		 * Decide whether to actually poll for completions, or just
+		 * wait for a later chance. If there seem to be plenty of
+		 * resources left, then just wait, since checking involves
+		 * reading a CE register, which is a relatively expensive
+		 * operation.
+		 */
+		resources = hif_get_free_queue_number(scn, pipe);
+		/*
+		 * If at least 50% of the total resources are still available,
+		 * don't bother checking again yet.
+		 */
+		if (resources > (host_ce_config[pipe].src_nentries >> 1)) {
+			return;
+		}
+	}
+#ifdef  ATH_11AC_TXCOMPACT
+	ce_per_engine_servicereap(scn, pipe);
+#else
+	ce_per_engine_service(scn, pipe);
+#endif
+}
+
+uint16_t hif_get_free_queue_number(struct ol_softc *scn, uint8_t pipe)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	struct HIF_CE_pipe_info *pipe_info = &(hif_state->pipe_info[pipe]);
+	uint16_t rv;
+
+	cdf_spin_lock_bh(&pipe_info->completion_freeq_lock);
+	rv = pipe_info->num_sends_allowed;
+	cdf_spin_unlock_bh(&pipe_info->completion_freeq_lock);
+	return rv;
+}
+
+/* Called by lower (CE) layer when a send to Target completes. */
+void
+hif_pci_ce_send_done(struct CE_handle *copyeng, void *ce_context,
+		     void *transfer_context, cdf_dma_addr_t CE_data,
+		     unsigned int nbytes, unsigned int transfer_id,
+		     unsigned int sw_index, unsigned int hw_index,
+		     unsigned int toeplitz_hash_result)
+{
+	struct HIF_CE_pipe_info *pipe_info =
+		(struct HIF_CE_pipe_info *)ce_context;
+	struct HIF_CE_state *hif_state = pipe_info->HIF_CE_state;
+	struct HIF_CE_completion_state *compl_state;
+	struct HIF_CE_completion_state *compl_queue_head, *compl_queue_tail;
+	unsigned int sw_idx = sw_index, hw_idx = hw_index;
+
+	compl_queue_head = compl_queue_tail = NULL;
+	do {
+		/*
+		 * For the send completion of an item in sendlist, just increment
+		 * num_sends_allowed. The upper layer callback will be triggered
+		 * when last fragment is done with send.
+		 */
+		if (transfer_context == CE_SENDLIST_ITEM_CTXT) {
+			cdf_spin_lock(&pipe_info->completion_freeq_lock);
+			pipe_info->num_sends_allowed++;
+			cdf_spin_unlock(&pipe_info->completion_freeq_lock);
+			continue;
+		}
+
+		cdf_spin_lock(&pipe_info->completion_freeq_lock);
+		compl_state = pipe_info->completion_freeq_head;
+		if (!compl_state) {
+			cdf_spin_unlock(&pipe_info->completion_freeq_lock);
+			HIF_ERROR("%s: ce_id:%d num_allowed:%d pipe_info:%p",
+					 __func__, pipe_info->pipe_num,
+					 pipe_info->num_sends_allowed,
+					 pipe_info);
+			ASSERT(0);
+			break;
+		}
+		pipe_info->completion_freeq_head = compl_state->next;
+		cdf_spin_unlock(&pipe_info->completion_freeq_lock);
+
+		compl_state->next = NULL;
+		compl_state->send_or_recv = HIF_CE_COMPLETE_SEND;
+		compl_state->copyeng = copyeng;
+		compl_state->ce_context = ce_context;
+		compl_state->transfer_context = transfer_context;
+		compl_state->data = CE_data;
+		compl_state->nbytes = nbytes;
+		compl_state->transfer_id = transfer_id;
+		compl_state->flags = 0;
+		compl_state->toeplitz_hash_result = toeplitz_hash_result;
+
+		/* Enqueue at end of local queue */
+		if (compl_queue_tail) {
+			compl_queue_tail->next = compl_state;
+		} else {
+			compl_queue_head = compl_state;
+		}
+		compl_queue_tail = compl_state;
+	} while (ce_completed_send_next(copyeng,
+			&ce_context, &transfer_context,
+			&CE_data, &nbytes, &transfer_id,
+			&sw_idx, &hw_idx,
+			&toeplitz_hash_result) == CDF_STATUS_SUCCESS);
+
+	if (compl_queue_head == NULL) {
+		/*
+		 * If only some of the items within a sendlist have completed,
+		 * don't invoke completion processing until the entire sendlist
+		 * has been sent.
+		 */
+		return;
+	}
+
+	cdf_spin_lock(&hif_state->completion_pendingq_lock);
+
+	/* Enqueue the local completion queue on the
+	 * per-device completion queue */
+	if (hif_state->completion_pendingq_head) {
+		hif_state->completion_pendingq_tail->next = compl_queue_head;
+		hif_state->completion_pendingq_tail = compl_queue_tail;
+		cdf_spin_unlock(&hif_state->completion_pendingq_lock);
+	} else {
+		hif_state->completion_pendingq_head = compl_queue_head;
+		hif_state->completion_pendingq_tail = compl_queue_tail;
+		cdf_spin_unlock(&hif_state->completion_pendingq_lock);
+
+		/* Alert the send completion service thread */
+		hif_completion_thread(hif_state);
+	}
+}
+
+/* Called by lower (CE) layer when data is received from the Target. */
+void
+hif_pci_ce_recv_data(struct CE_handle *copyeng, void *ce_context,
+		     void *transfer_context, cdf_dma_addr_t CE_data,
+		     unsigned int nbytes, unsigned int transfer_id,
+		     unsigned int flags)
+{
+	struct HIF_CE_pipe_info *pipe_info =
+		(struct HIF_CE_pipe_info *)ce_context;
+	struct HIF_CE_state *hif_state = pipe_info->HIF_CE_state;
+	struct ol_softc *scn = hif_state->scn;
+	struct HIF_CE_completion_state *compl_state;
+	struct HIF_CE_completion_state *compl_queue_head, *compl_queue_tail;
+
+	compl_queue_head = compl_queue_tail = NULL;
+	do {
+		cdf_spin_lock(&pipe_info->completion_freeq_lock);
+		compl_state = pipe_info->completion_freeq_head;
+		ASSERT(compl_state != NULL);
+		pipe_info->completion_freeq_head = compl_state->next;
+		cdf_spin_unlock(&pipe_info->completion_freeq_lock);
+
+		compl_state->next = NULL;
+		compl_state->send_or_recv = HIF_CE_COMPLETE_RECV;
+		compl_state->copyeng = copyeng;
+		compl_state->ce_context = ce_context;
+		compl_state->transfer_context = transfer_context;
+		compl_state->data = CE_data;
+		compl_state->nbytes = nbytes;
+		compl_state->transfer_id = transfer_id;
+		compl_state->flags = flags;
+
+		/* Enqueue at end of local queue */
+		if (compl_queue_tail) {
+			compl_queue_tail->next = compl_state;
+		} else {
+			compl_queue_head = compl_state;
+		}
+		compl_queue_tail = compl_state;
+
+		cdf_nbuf_unmap_single(scn->cdf_dev,
+				      (cdf_nbuf_t) transfer_context,
+				      CDF_DMA_FROM_DEVICE);
+
+		/*
+		 * EV #112693 - [Peregrine][ES1][WB342][Win8x86][Performance]
+		 * BSoD_0x133 occurred in VHT80 UDP_DL
+		 * Break out DPC by force if number of loops in
+		 * hif_pci_ce_recv_data reaches MAX_NUM_OF_RECEIVES to avoid
+		 * spending too long time in DPC for each interrupt handling.
+		 * Schedule another DPC to avoid data loss if we had taken
+		 * force-break action before apply to Windows OS only
+		 * currently, Linux/MAC os can expand to their platform
+		 * if necessary
+		 */
+
+		/* Set up force_break flag if num of receices reaches
+		 * MAX_NUM_OF_RECEIVES */
+		scn->receive_count++;
+		if (cdf_unlikely(hif_max_num_receives_reached(
+				scn->receive_count))) {
+			scn->force_break = 1;
+			break;
+		}
+	} while (ce_completed_recv_next(copyeng, &ce_context, &transfer_context,
+					&CE_data, &nbytes, &transfer_id,
+					&flags) == CDF_STATUS_SUCCESS);
+
+	cdf_spin_lock(&hif_state->completion_pendingq_lock);
+
+	/* Enqueue the local completion queue on the
+	 * per-device completion queue */
+	if (hif_state->completion_pendingq_head) {
+		hif_state->completion_pendingq_tail->next = compl_queue_head;
+		hif_state->completion_pendingq_tail = compl_queue_tail;
+		cdf_spin_unlock(&hif_state->completion_pendingq_lock);
+	} else {
+		hif_state->completion_pendingq_head = compl_queue_head;
+		hif_state->completion_pendingq_tail = compl_queue_tail;
+		cdf_spin_unlock(&hif_state->completion_pendingq_lock);
+
+		/* Alert the recv completion service thread */
+		hif_completion_thread(hif_state);
+	}
+}
+
+/* TBDXXX: Set CE High Watermark; invoke txResourceAvailHandler in response */
+
+void
+hif_post_init(struct ol_softc *scn, void *unused,
+	      struct hif_msg_callbacks *callbacks)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+
+#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
+	spin_lock_init(&pcie_access_log_lock);
+#endif
+	/* Save callbacks for later installation */
+	cdf_mem_copy(&hif_state->msg_callbacks_pending, callbacks,
+		 sizeof(hif_state->msg_callbacks_pending));
+
+}
+
+static void hif_pci_free_complete_state(struct HIF_CE_pipe_info *pipe_info)
+{
+    struct HIF_CE_completion_state_list *tmp_list;
+
+    while (pipe_info->completion_space_list) {
+        tmp_list = pipe_info->completion_space_list;
+        pipe_info->completion_space_list = tmp_list->next;
+        cdf_mem_free(tmp_list);
+    }
+}
+
+static int hif_alloc_complete_state_list(
+	struct HIF_CE_pipe_info *pipe_info,
+	int completions_needed)
+{
+	struct HIF_CE_completion_state *compl_state;
+	struct HIF_CE_completion_state_list *tmp_list;
+	int i;
+	int idx;
+	int num_list;
+	int allocated_node;
+	int num_in_batch;
+	size_t len;
+
+	allocated_node = 0;
+	num_list = (completions_needed + HIF_CE_COMPLETE_STATE_NUM -1);
+	num_list /= HIF_CE_COMPLETE_STATE_NUM;
+	for (idx = 0; idx < num_list; idx++) {
+		if (completions_needed - allocated_node >=
+			HIF_CE_COMPLETE_STATE_NUM)
+			num_in_batch = HIF_CE_COMPLETE_STATE_NUM;
+		else
+			num_in_batch = completions_needed - allocated_node;
+		if (num_in_batch <= 0)
+			break;
+		len = num_in_batch * sizeof(struct HIF_CE_completion_state) +
+			    sizeof(struct HIF_CE_completion_state_list);
+		/* Allocate structures to track pending send/recv completions */
+		tmp_list =
+			(struct HIF_CE_completion_state_list *)
+			cdf_mem_malloc(len);
+		if (!tmp_list) {
+			HIF_ERROR("%s: compl_state has no mem", __func__);
+			hif_pci_free_complete_state(pipe_info);
+			return -1;
+		}
+		cdf_mem_zero(tmp_list, len);
+		compl_state = (struct HIF_CE_completion_state *)
+		((uint8_t *)tmp_list +
+			 sizeof(struct HIF_CE_completion_state_list));
+		for (i = 0; i < num_in_batch; i++) {
+			compl_state->send_or_recv = HIF_CE_COMPLETE_FREE;
+			compl_state->next = NULL;
+			if (pipe_info->completion_freeq_head)
+				pipe_info->completion_freeq_tail->next =
+					compl_state;
+			else
+				pipe_info->completion_freeq_head =
+					compl_state;
+			pipe_info->completion_freeq_tail = compl_state;
+			compl_state++;
+			allocated_node++;
+		}
+		if (pipe_info->completion_space_list == NULL) {
+			pipe_info->completion_space_list = tmp_list;
+			tmp_list->next = NULL;
+		} else {
+			tmp_list->next =
+				pipe_info->completion_space_list;
+			pipe_info->completion_space_list = tmp_list;
+		}
+	}
+	cdf_spinlock_init(&pipe_info->completion_freeq_lock);
+	return 0;
+}
+int hif_completion_thread_startup(struct HIF_CE_state *hif_state)
+{
+	struct CE_handle *ce_diag = hif_state->ce_diag;
+	int pipe_num;
+	struct ol_softc *scn = hif_state->scn;
+
+	/* daemonize("hif_compl_thread"); */
+
+	cdf_spinlock_init(&hif_state->completion_pendingq_lock);
+	hif_state->completion_pendingq_head =
+		hif_state->completion_pendingq_tail = NULL;
+
+	if (scn->ce_count == 0) {
+		HIF_ERROR("%s: Invalid ce_count\n", __func__);
+		return -EINVAL;
+	}
+	A_TARGET_ACCESS_LIKELY(scn);
+	for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) {
+		struct CE_attr attr;
+		struct HIF_CE_pipe_info *pipe_info;
+		int completions_needed;
+
+		pipe_info = &hif_state->pipe_info[pipe_num];
+		if (pipe_info->ce_hdl == ce_diag) {
+			continue;       /* Handle Diagnostic CE specially */
+		}
+		attr = host_ce_config[pipe_num];
+		completions_needed = 0;
+		if (attr.src_nentries) {
+			/* pipe used to send to target */
+			HIF_INFO_MED("%s: pipe_num:%d pipe_info:0x%p",
+					 __func__, pipe_num, pipe_info);
+			ce_send_cb_register(pipe_info->ce_hdl,
+					    hif_pci_ce_send_done, pipe_info,
+					    attr.flags & CE_ATTR_DISABLE_INTR);
+			completions_needed += attr.src_nentries;
+			pipe_info->num_sends_allowed = attr.src_nentries - 1;
+		}
+		if (attr.dest_nentries) {
+			/* pipe used to receive from target */
+			ce_recv_cb_register(pipe_info->ce_hdl,
+					    hif_pci_ce_recv_data, pipe_info,
+					    attr.flags & CE_ATTR_DISABLE_INTR);
+			completions_needed += attr.dest_nentries;
+		}
+
+		pipe_info->completion_freeq_head =
+			pipe_info->completion_freeq_tail = NULL;
+		if (completions_needed > 0) {
+			int ret;
+
+			ret = hif_alloc_complete_state_list(pipe_info,
+				completions_needed);
+			if (ret != 0) {
+				HIF_ERROR("%s: ce_id = %d, no mem",
+					  __func__, pipe_info->pipe_num);
+				return ret;
+			}
+		}
+	}
+	A_TARGET_ACCESS_UNLIKELY(scn);
+	return 0;
+}
+
+void hif_completion_thread_shutdown(struct HIF_CE_state *hif_state)
+{
+	struct HIF_CE_completion_state *compl_state;
+	struct HIF_CE_pipe_info *pipe_info;
+	struct ol_softc *scn = hif_state->scn;
+	int pipe_num;
+
+	/*
+	 * Drop pending completions.  These have already been
+	 * reported by the CE layer to us but we have not yet
+	 * passed them upstack.
+	 */
+	while ((compl_state = hif_state->completion_pendingq_head) != NULL) {
+		cdf_nbuf_t netbuf;
+
+		netbuf = (cdf_nbuf_t) compl_state->transfer_context;
+		cdf_nbuf_free(netbuf);
+
+		hif_state->completion_pendingq_head = compl_state->next;
+
+		/*
+		 * NB: Don't bother to place compl_state on pipe's free queue,
+		 * because we'll free underlying memory for the free queues
+		 * in a moment anyway.
+		 */
+	}
+
+	for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) {
+		pipe_info = &hif_state->pipe_info[pipe_num];
+		hif_pci_free_complete_state(pipe_info);
+		cdf_spinlock_destroy(&pipe_info->completion_freeq_lock);
+	}
+
+	/* hif_state->compl_thread = NULL; */
+	/* complete_and_exit(&hif_state->compl_thread_done, 0); */
+}
+
+/*
+ * This thread provides a context in which send/recv completions
+ * are handled.
+ *
+ * Note: HIF installs callback functions with the CE layer.
+ * Those functions are called directly (e.g. in interrupt context).
+ * Upper layers (e.g. HTC) have installed callbacks with HIF which
+ * expect to be called in a thread context. This is where that
+ * conversion occurs.
+ *
+ * TBDXXX: Currently we use just one thread for all pipes.
+ * This might be sufficient or we might need multiple threads.
+ */
+int
+/* hif_completion_thread(void *hif_dev) */
+hif_completion_thread(struct HIF_CE_state *hif_state)
+{
+	struct hif_msg_callbacks *msg_callbacks =
+		&hif_state->msg_callbacks_current;
+	struct HIF_CE_completion_state *compl_state;
+
+	/* Allow only one instance of the thread to execute at a time to
+	 * prevent out of order processing of messages - this is bad for higher
+	 * layer code
+	 */
+	if (!cdf_atomic_dec_and_test(&hif_state->hif_thread_idle)) {
+		/* We were not the lucky one */
+		cdf_atomic_inc(&hif_state->hif_thread_idle);
+		return 0;
+	}
+
+	if (!msg_callbacks->fwEventHandler
+	    || !msg_callbacks->txCompletionHandler
+	    || !msg_callbacks->rxCompletionHandler) {
+		return 0;
+	}
+	while (atomic_read(&hif_state->fw_event_pending) > 0) {
+		/*
+		 * Clear pending state before handling, in case there's
+		 * another while we process the first.
+		 */
+		atomic_set(&hif_state->fw_event_pending, 0);
+		msg_callbacks->fwEventHandler(msg_callbacks->Context,
+					      CDF_STATUS_E_FAILURE);
+	}
+
+	if (hif_state->scn->target_status == OL_TRGET_STATUS_RESET)
+		return 0;
+
+	for (;; ) {
+		struct HIF_CE_pipe_info *pipe_info;
+		int send_done = 0;
+
+		cdf_spin_lock(&hif_state->completion_pendingq_lock);
+
+		if (!hif_state->completion_pendingq_head) {
+			/* We are atomically sure that
+			 * there is no pending work */
+			cdf_atomic_inc(&hif_state->hif_thread_idle);
+			cdf_spin_unlock(&hif_state->completion_pendingq_lock);
+			break;  /* All pending completions are handled */
+		}
+
+		/* Dequeue the first unprocessed but completed transfer */
+		compl_state = hif_state->completion_pendingq_head;
+		hif_state->completion_pendingq_head = compl_state->next;
+		cdf_spin_unlock(&hif_state->completion_pendingq_lock);
+
+		pipe_info = (struct HIF_CE_pipe_info *)compl_state->ce_context;
+		if (compl_state->send_or_recv == HIF_CE_COMPLETE_SEND) {
+			msg_callbacks->txCompletionHandler(msg_callbacks->
+				   Context,
+				   compl_state->
+				   transfer_context,
+				   compl_state->
+				   transfer_id,
+				   compl_state->toeplitz_hash_result);
+			send_done = 1;
+		} else {
+			/* compl_state->send_or_recv == HIF_CE_COMPLETE_RECV */
+			cdf_nbuf_t netbuf;
+			unsigned int nbytes;
+
+			atomic_inc(&pipe_info->recv_bufs_needed);
+			hif_post_recv_buffers(hif_state->scn);
+
+			netbuf = (cdf_nbuf_t) compl_state->transfer_context;
+			nbytes = compl_state->nbytes;
+			/*
+			 * To see the following debug output,
+			 * enable the HIF_PCI_DEBUG flag in
+			 * the debug module declaration in this source file
+			 */
+			HIF_DBG("%s: netbuf=%p, nbytes=%d",
+				__func__, netbuf, nbytes);
+			if (nbytes <= pipe_info->buf_sz) {
+				cdf_nbuf_set_pktlen(netbuf, nbytes);
+				msg_callbacks->
+				rxCompletionHandler(msg_callbacks->Context,
+						    netbuf,
+						    pipe_info->pipe_num);
+			} else {
+				HIF_ERROR(
+					"%s: Invalid Rx msg buf:%p nbytes:%d",
+					 __func__, netbuf, nbytes);
+				cdf_nbuf_free(netbuf);
+			}
+		}
+
+		/* Recycle completion state back to the pipe it came from. */
+		compl_state->next = NULL;
+		compl_state->send_or_recv = HIF_CE_COMPLETE_FREE;
+		cdf_spin_lock(&pipe_info->completion_freeq_lock);
+		if (pipe_info->completion_freeq_head) {
+			pipe_info->completion_freeq_tail->next = compl_state;
+		} else {
+			pipe_info->completion_freeq_head = compl_state;
+		}
+		pipe_info->completion_freeq_tail = compl_state;
+		pipe_info->num_sends_allowed += send_done;
+		cdf_spin_unlock(&pipe_info->completion_freeq_lock);
+	}
+
+	return 0;
+}
+
+/*
+ * Install pending msg callbacks.
+ *
+ * TBDXXX: This hack is needed because upper layers install msg callbacks
+ * for use with HTC before BMI is done; yet this HIF implementation
+ * needs to continue to use BMI msg callbacks. Really, upper layers
+ * should not register HTC callbacks until AFTER BMI phase.
+ */
+static void hif_msg_callbacks_install(struct ol_softc *scn)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+
+	cdf_mem_copy(&hif_state->msg_callbacks_current,
+		 &hif_state->msg_callbacks_pending,
+		 sizeof(hif_state->msg_callbacks_pending));
+}
+
+void hif_claim_device(struct ol_softc *scn, void *claimedContext)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+
+	hif_state->claimedContext = claimedContext;
+}
+
+void hif_release_device(struct ol_softc *scn)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+
+	hif_state->claimedContext = NULL;
+}
+
+void
+hif_get_default_pipe(struct ol_softc *scn, uint8_t *ULPipe, uint8_t *DLPipe)
+{
+	int ul_is_polled, dl_is_polled;
+
+	(void)hif_map_service_to_pipe(scn, HTC_CTRL_RSVD_SVC,
+		ULPipe, DLPipe, &ul_is_polled, &dl_is_polled);
+}
+
+/* TBDXXX - temporary mapping while we have too few CE's */
+int
+hif_map_service_to_pipe(struct ol_softc *scn, uint16_t ServiceId,
+			uint8_t *ULPipe, uint8_t *DLPipe, int *ul_is_polled,
+			int *dl_is_polled)
+{
+	int status = CDF_STATUS_SUCCESS;
+
+	*dl_is_polled = 0;  /* polling for received messages not supported */
+	switch (ServiceId) {
+	case HTT_DATA_MSG_SVC:
+		/*
+		 * Host->target HTT gets its own pipe, so it can be polled
+		 * while other pipes are interrupt driven.
+		 */
+		*ULPipe = 4;
+		/*
+		 * Use the same target->host pipe for HTC ctrl,
+		 * HTC raw streams, and HTT.
+		 */
+		*DLPipe = 1;
+		break;
+
+	case HTC_CTRL_RSVD_SVC:
+		*ULPipe = 0;
+		*DLPipe = 2;
+		break;
+
+	case HTC_RAW_STREAMS_SVC:
+		/*
+		 * Note: HTC_RAW_STREAMS_SVC is currently unused, and
+		 * HTC_CTRL_RSVD_SVC could share the same pipe as the
+		 * WMI services.  So, if another CE is needed, change
+		 * this to *ULPipe = 3, which frees up CE 0.
+		 */
+		/**ULPipe = 3; */
+		*ULPipe = 0;
+		*DLPipe = 2;
+		break;
+
+	case WMI_DATA_BK_SVC:
+		/*
+		 * To avoid some confusions, better to introduce new EP-ping
+		 * service instead of using existed services. Until the main
+		 * framework support this, keep this design.
+		 */
+		if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) {
+			*ULPipe = 4;
+			*DLPipe = 1;
+			break;
+		}
+	case WMI_DATA_BE_SVC:
+	case WMI_DATA_VI_SVC:
+	case WMI_DATA_VO_SVC:
+
+	case WMI_CONTROL_SVC:
+		*ULPipe = 3;
+		*DLPipe = 2;
+		break;
+
+	case WDI_IPA_TX_SVC:
+		*ULPipe = 5;
+		break;
+
+	/* pipe 5 unused   */
+	/* pipe 6 reserved */
+	/* pipe 7 reserved */
+
+	default:
+		status = CDF_STATUS_E_INVAL;
+		break;
+	}
+	*ul_is_polled =
+		(host_ce_config[*ULPipe].flags & CE_ATTR_DISABLE_INTR) != 0;
+
+	return status;
+}
+
+/**
+ * hif_dump_pipe_debug_count() - Log error count
+ * @scn: ol_softc pointer.
+ *
+ * Output the pipe error counts of each pipe to log file
+ *
+ * Return: N/A
+ */
+void hif_dump_pipe_debug_count(struct ol_softc *scn)
+{
+	struct HIF_CE_state *hif_state;
+	int pipe_num;
+
+	if (scn == NULL) {
+		HIF_ERROR("%s scn is NULL", __func__);
+		return;
+	}
+	hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	if (hif_state == NULL) {
+		HIF_ERROR("%s hif_state is NULL", __func__);
+		return;
+	}
+	for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) {
+		struct HIF_CE_pipe_info *pipe_info;
+
+	pipe_info = &hif_state->pipe_info[pipe_num];
+
+	if (pipe_info->nbuf_alloc_err_count > 0 ||
+			pipe_info->nbuf_dma_err_count > 0 ||
+			pipe_info->nbuf_ce_enqueue_err_count)
+		HIF_ERROR(
+			"%s: pipe_id = %d, recv_bufs_needed = %d, nbuf_alloc_err_count = %u, nbuf_dma_err_count = %u, nbuf_ce_enqueue_err_count = %u",
+			__func__, pipe_info->pipe_num,
+			atomic_read(&pipe_info->recv_bufs_needed),
+			pipe_info->nbuf_alloc_err_count,
+			pipe_info->nbuf_dma_err_count,
+			pipe_info->nbuf_ce_enqueue_err_count);
+	}
+}
+
+static int hif_post_recv_buffers_for_pipe(struct HIF_CE_pipe_info *pipe_info)
+{
+	struct CE_handle *ce_hdl;
+	cdf_size_t buf_sz;
+	struct HIF_CE_state *hif_state = pipe_info->HIF_CE_state;
+	struct ol_softc *scn = hif_state->scn;
+	CDF_STATUS ret;
+	uint32_t bufs_posted = 0;
+
+	buf_sz = pipe_info->buf_sz;
+	if (buf_sz == 0) {
+		/* Unused Copy Engine */
+		return 0;
+	}
+
+	ce_hdl = pipe_info->ce_hdl;
+
+	cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock);
+	while (atomic_read(&pipe_info->recv_bufs_needed) > 0) {
+		cdf_dma_addr_t CE_data;      /* CE space buffer address */
+		cdf_nbuf_t nbuf;
+		int status;
+
+		atomic_dec(&pipe_info->recv_bufs_needed);
+		cdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock);
+
+		nbuf = cdf_nbuf_alloc(scn->cdf_dev, buf_sz, 0, 4, false);
+		if (!nbuf) {
+			cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock);
+			pipe_info->nbuf_alloc_err_count++;
+			cdf_spin_unlock_bh(
+				&pipe_info->recv_bufs_needed_lock);
+			HIF_ERROR(
+				"%s buf alloc error [%d] needed %d, nbuf_alloc_err_count = %u",
+				 __func__, pipe_info->pipe_num,
+				 atomic_read(&pipe_info->recv_bufs_needed),
+				pipe_info->nbuf_alloc_err_count);
+			atomic_inc(&pipe_info->recv_bufs_needed);
+			return 1;
+		}
+
+		/*
+		 * cdf_nbuf_peek_header(nbuf, &data, &unused);
+		 * CE_data = dma_map_single(dev, data, buf_sz, );
+		 * DMA_FROM_DEVICE);
+		 */
+		ret =
+			cdf_nbuf_map_single(scn->cdf_dev, nbuf,
+					    CDF_DMA_FROM_DEVICE);
+
+		if (unlikely(ret != CDF_STATUS_SUCCESS)) {
+			cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock);
+			pipe_info->nbuf_dma_err_count++;
+			cdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock);
+			HIF_ERROR(
+				"%s buf alloc error [%d] needed %d, nbuf_dma_err_count = %u",
+				 __func__, pipe_info->pipe_num,
+				 atomic_read(&pipe_info->recv_bufs_needed),
+				pipe_info->nbuf_dma_err_count);
+			cdf_nbuf_free(nbuf);
+			atomic_inc(&pipe_info->recv_bufs_needed);
+			return 1;
+		}
+
+		CE_data = cdf_nbuf_get_frag_paddr_lo(nbuf, 0);
+
+		cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_data,
+					       buf_sz, DMA_FROM_DEVICE);
+		status = ce_recv_buf_enqueue(ce_hdl, (void *)nbuf, CE_data);
+		CDF_ASSERT(status == CDF_STATUS_SUCCESS);
+		if (status != EOK) {
+			cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock);
+			pipe_info->nbuf_ce_enqueue_err_count++;
+			cdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock);
+			HIF_ERROR(
+				"%s buf alloc error [%d] needed %d, nbuf_alloc_err_count = %u",
+				__func__, pipe_info->pipe_num,
+				atomic_read(&pipe_info->recv_bufs_needed),
+				pipe_info->nbuf_ce_enqueue_err_count);
+			atomic_inc(&pipe_info->recv_bufs_needed);
+			cdf_nbuf_free(nbuf);
+			return 1;
+		}
+
+		cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock);
+		bufs_posted++;
+	}
+	pipe_info->nbuf_alloc_err_count =
+		(pipe_info->nbuf_alloc_err_count > bufs_posted)?
+		pipe_info->nbuf_alloc_err_count - bufs_posted : 0;
+	pipe_info->nbuf_dma_err_count =
+		(pipe_info->nbuf_dma_err_count > bufs_posted)?
+		pipe_info->nbuf_dma_err_count - bufs_posted : 0;
+	pipe_info->nbuf_ce_enqueue_err_count =
+		(pipe_info->nbuf_ce_enqueue_err_count > bufs_posted)?
+	     pipe_info->nbuf_ce_enqueue_err_count - bufs_posted : 0;
+
+	cdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock);
+
+	return 0;
+}
+
+/*
+ * Try to post all desired receive buffers for all pipes.
+ * Returns 0 if all desired buffers are posted,
+ * non-zero if were were unable to completely
+ * replenish receive buffers.
+ */
+static int hif_post_recv_buffers(struct ol_softc *scn)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	int pipe_num, rv = 0;
+
+	A_TARGET_ACCESS_LIKELY(scn);
+	for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) {
+		struct HIF_CE_pipe_info *pipe_info;
+
+		pipe_info = &hif_state->pipe_info[pipe_num];
+		if (hif_post_recv_buffers_for_pipe(pipe_info)) {
+			rv = 1;
+			goto done;
+		}
+	}
+
+done:
+	A_TARGET_ACCESS_UNLIKELY(scn);
+
+	return rv;
+}
+
+CDF_STATUS hif_start(struct ol_softc *scn)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+
+	if (hif_completion_thread_startup(hif_state))
+		return CDF_STATUS_E_FAILURE;
+
+	hif_msg_callbacks_install(scn);
+
+	/* Post buffers once to start things off. */
+	(void)hif_post_recv_buffers(scn);
+
+	hif_state->started = true;
+
+	return CDF_STATUS_SUCCESS;
+}
+
+#ifdef WLAN_FEATURE_FASTPATH
+/**
+ * hif_enable_fastpath() Update that we have enabled fastpath mode
+ * @hif_device: HIF context
+ *
+ * For use in data path
+ *
+ * Retrun: void
+ */
+void
+hif_enable_fastpath(struct ol_softc *hif_device)
+{
+	HIF_INFO("Enabling fastpath mode\n");
+	hif_device->fastpath_mode_on = 1;
+}
+#endif /* WLAN_FEATURE_FASTPATH */
+
+void hif_recv_buffer_cleanup_on_pipe(struct HIF_CE_pipe_info *pipe_info)
+{
+	struct ol_softc *scn;
+	struct CE_handle *ce_hdl;
+	uint32_t buf_sz;
+	struct HIF_CE_state *hif_state;
+	cdf_nbuf_t netbuf;
+	cdf_dma_addr_t CE_data;
+	void *per_CE_context;
+
+	buf_sz = pipe_info->buf_sz;
+	if (buf_sz == 0) {
+		/* Unused Copy Engine */
+		return;
+	}
+
+	hif_state = pipe_info->HIF_CE_state;
+	if (!hif_state->started) {
+		return;
+	}
+
+	scn = hif_state->scn;
+	ce_hdl = pipe_info->ce_hdl;
+
+	if (scn->cdf_dev == NULL) {
+		return;
+	}
+	while (ce_revoke_recv_next
+		       (ce_hdl, &per_CE_context, (void **)&netbuf,
+			&CE_data) == CDF_STATUS_SUCCESS) {
+		cdf_nbuf_unmap_single(scn->cdf_dev, netbuf,
+				      CDF_DMA_FROM_DEVICE);
+		cdf_nbuf_free(netbuf);
+	}
+}
+
+void hif_send_buffer_cleanup_on_pipe(struct HIF_CE_pipe_info *pipe_info)
+{
+	struct CE_handle *ce_hdl;
+	struct HIF_CE_state *hif_state;
+	cdf_nbuf_t netbuf;
+	void *per_CE_context;
+	cdf_dma_addr_t CE_data;
+	unsigned int nbytes;
+	unsigned int id;
+	uint32_t buf_sz;
+	uint32_t toeplitz_hash_result;
+
+	buf_sz = pipe_info->buf_sz;
+	if (buf_sz == 0) {
+		/* Unused Copy Engine */
+		return;
+	}
+
+	hif_state = pipe_info->HIF_CE_state;
+	if (!hif_state->started) {
+		return;
+	}
+
+	ce_hdl = pipe_info->ce_hdl;
+
+	while (ce_cancel_send_next
+		       (ce_hdl, &per_CE_context,
+		       (void **)&netbuf, &CE_data, &nbytes,
+		       &id, &toeplitz_hash_result) == CDF_STATUS_SUCCESS) {
+		if (netbuf != CE_SENDLIST_ITEM_CTXT) {
+			/*
+			 * Packets enqueued by htt_h2t_ver_req_msg() and
+			 * htt_h2t_rx_ring_cfg_msg_ll() have already been
+			 * freed in htt_htc_misc_pkt_pool_free() in
+			 * wlantl_close(), so do not free them here again
+			 * by checking whether it's the EndPoint
+			 * which they are queued in.
+			 */
+			if (id == hif_state->scn->htc_endpoint)
+				return;
+			/* Indicate the completion to higer
+			 * layer to free the buffer */
+			hif_state->msg_callbacks_current.
+			txCompletionHandler(hif_state->
+					    msg_callbacks_current.Context,
+					    netbuf, id, toeplitz_hash_result);
+		}
+	}
+}
+
+/*
+ * Cleanup residual buffers for device shutdown:
+ *    buffers that were enqueued for receive
+ *    buffers that were to be sent
+ * Note: Buffers that had completed but which were
+ * not yet processed are on a completion queue. They
+ * are handled when the completion thread shuts down.
+ */
+void hif_buffer_cleanup(struct HIF_CE_state *hif_state)
+{
+	int pipe_num;
+
+	for (pipe_num = 0; pipe_num < hif_state->scn->ce_count; pipe_num++) {
+		struct HIF_CE_pipe_info *pipe_info;
+
+		pipe_info = &hif_state->pipe_info[pipe_num];
+		hif_recv_buffer_cleanup_on_pipe(pipe_info);
+		hif_send_buffer_cleanup_on_pipe(pipe_info);
+	}
+}
+
+void hif_flush_surprise_remove(struct ol_softc *scn)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	hif_buffer_cleanup(hif_state);
+}
+
+void hif_stop(struct ol_softc *scn)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	int pipe_num;
+
+	scn->hif_init_done = false;
+	if (hif_state->started) {
+		/* sync shutdown */
+		hif_completion_thread_shutdown(hif_state);
+		hif_completion_thread(hif_state);
+	} else {
+		hif_completion_thread_shutdown(hif_state);
+	}
+
+	/*
+	 * At this point, asynchronous threads are stopped,
+	 * The Target should not DMA nor interrupt, Host code may
+	 * not initiate anything more.  So we just need to clean
+	 * up Host-side state.
+	 */
+
+	if (scn->athdiag_procfs_inited) {
+		athdiag_procfs_remove();
+		scn->athdiag_procfs_inited = false;
+	}
+
+	hif_buffer_cleanup(hif_state);
+
+	for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) {
+		struct HIF_CE_pipe_info *pipe_info;
+
+		pipe_info = &hif_state->pipe_info[pipe_num];
+		if (pipe_info->ce_hdl) {
+			ce_fini(pipe_info->ce_hdl);
+			pipe_info->ce_hdl = NULL;
+			pipe_info->buf_sz = 0;
+		}
+	}
+
+	if (hif_state->sleep_timer_init) {
+		cdf_softirq_timer_cancel(&hif_state->sleep_timer);
+		cdf_softirq_timer_free(&hif_state->sleep_timer);
+		hif_state->sleep_timer_init = false;
+	}
+
+	hif_state->started = false;
+}
+
+#define ADRASTEA_SRC_WR_INDEX_OFFSET 0x3C
+#define ADRASTEA_DST_WR_INDEX_OFFSET 0x40
+
+
+static struct shadow_reg_cfg target_shadow_reg_cfg_map[] = {
+	{ 0, ADRASTEA_SRC_WR_INDEX_OFFSET},
+	{ 3, ADRASTEA_SRC_WR_INDEX_OFFSET},
+	{ 4, ADRASTEA_SRC_WR_INDEX_OFFSET},
+	{ 5, ADRASTEA_SRC_WR_INDEX_OFFSET},
+	{ 7, ADRASTEA_SRC_WR_INDEX_OFFSET},
+	{ 1, ADRASTEA_DST_WR_INDEX_OFFSET},
+	{ 2, ADRASTEA_DST_WR_INDEX_OFFSET},
+	{ 7, ADRASTEA_DST_WR_INDEX_OFFSET},
+	{ 8, ADRASTEA_DST_WR_INDEX_OFFSET},
+};
+
+
+
+/* CE_PCI TABLE */
+/*
+ * NOTE: the table below is out of date, though still a useful reference.
+ * Refer to target_service_to_ce_map and hif_map_service_to_pipe for the actual
+ * mapping of HTC services to HIF pipes.
+ */
+/*
+ * This authoritative table defines Copy Engine configuration and the mapping
+ * of services/endpoints to CEs.  A subset of this information is passed to
+ * the Target during startup as a prerequisite to entering BMI phase.
+ * See:
+ *    target_service_to_ce_map - Target-side mapping
+ *    hif_map_service_to_pipe      - Host-side mapping
+ *    target_ce_config         - Target-side configuration
+ *    host_ce_config           - Host-side configuration
+   ============================================================================
+   Purpose    | Service / Endpoint   | CE   | Dire | Xfer     | Xfer
+ |                      |      | ctio | Size     | Frequency
+ |                      |      | n    |          |
+   ============================================================================
+   tx         | HTT_DATA (downlink)  | CE 0 | h->t | medium - | very frequent
+   descriptor |                      |      |      | O(100B)  | and regular
+   download   |                      |      |      |          |
+   ----------------------------------------------------------------------------
+   rx         | HTT_DATA (uplink)    | CE 1 | t->h | small -  | frequent and
+   indication |                      |      |      | O(10B)   | regular
+   upload     |                      |      |      |          |
+   ----------------------------------------------------------------------------
+   MSDU       | DATA_BK (uplink)     | CE 2 | t->h | large -  | rare
+   upload     |                      |      |      | O(1000B) | (frequent
+   e.g. noise |                      |      |      |          | during IP1.0
+   packets    |                      |      |      |          | testing)
+   ----------------------------------------------------------------------------
+   MSDU       | DATA_BK (downlink)   | CE 3 | h->t | large -  | very rare
+   download   |                      |      |      | O(1000B) | (frequent
+   e.g.       |                      |      |      |          | during IP1.0
+   misdirecte |                      |      |      |          | testing)
+   d EAPOL    |                      |      |      |          |
+   packets    |                      |      |      |          |
+   ----------------------------------------------------------------------------
+   n/a        | DATA_BE, DATA_VI     | CE 2 | t->h |          | never(?)
+ | DATA_VO (uplink)     |      |      |          |
+   ----------------------------------------------------------------------------
+   n/a        | DATA_BE, DATA_VI     | CE 3 | h->t |          | never(?)
+ | DATA_VO (downlink)   |      |      |          |
+   ----------------------------------------------------------------------------
+   WMI events | WMI_CONTROL (uplink) | CE 4 | t->h | medium - | infrequent
+ |                      |      |      | O(100B)  |
+   ----------------------------------------------------------------------------
+   WMI        | WMI_CONTROL          | CE 5 | h->t | medium - | infrequent
+   messages   | (downlink)           |      |      | O(100B)  |
+ |                      |      |      |          |
+   ----------------------------------------------------------------------------
+   n/a        | HTC_CTRL_RSVD,       | CE 1 | t->h |          | never(?)
+ | HTC_RAW_STREAMS      |      |      |          |
+ | (uplink)             |      |      |          |
+   ----------------------------------------------------------------------------
+   n/a        | HTC_CTRL_RSVD,       | CE 0 | h->t |          | never(?)
+ | HTC_RAW_STREAMS      |      |      |          |
+ | (downlink)           |      |      |          |
+   ----------------------------------------------------------------------------
+   diag       | none (raw CE)        | CE 7 | t<>h |    4     | Diag Window
+ |                      |      |      |          | infrequent
+   ============================================================================
+ */
+
+/*
+ * Map from service/endpoint to Copy Engine.
+ * This table is derived from the CE_PCI TABLE, above.
+ * It is passed to the Target at startup for use by firmware.
+ */
+static struct service_to_pipe target_service_to_ce_map_wlan[] = {
+	{
+		WMI_DATA_VO_SVC,
+		PIPEDIR_OUT,    /* out = UL = host -> target */
+		3,
+	},
+	{
+		WMI_DATA_VO_SVC,
+		PIPEDIR_IN,     /* in = DL = target -> host */
+		2,
+	},
+	{
+		WMI_DATA_BK_SVC,
+		PIPEDIR_OUT,    /* out = UL = host -> target */
+		3,
+	},
+	{
+		WMI_DATA_BK_SVC,
+		PIPEDIR_IN,     /* in = DL = target -> host */
+		2,
+	},
+	{
+		WMI_DATA_BE_SVC,
+		PIPEDIR_OUT,    /* out = UL = host -> target */
+		3,
+	},
+	{
+		WMI_DATA_BE_SVC,
+		PIPEDIR_IN,     /* in = DL = target -> host */
+		2,
+	},
+	{
+		WMI_DATA_VI_SVC,
+		PIPEDIR_OUT,    /* out = UL = host -> target */
+		3,
+	},
+	{
+		WMI_DATA_VI_SVC,
+		PIPEDIR_IN,     /* in = DL = target -> host */
+		2,
+	},
+	{
+		WMI_CONTROL_SVC,
+		PIPEDIR_OUT,    /* out = UL = host -> target */
+		3,
+	},
+	{
+		WMI_CONTROL_SVC,
+		PIPEDIR_IN,     /* in = DL = target -> host */
+		2,
+	},
+	{
+		HTC_CTRL_RSVD_SVC,
+		PIPEDIR_OUT,    /* out = UL = host -> target */
+		0,              /* could be moved to 3 (share with WMI) */
+	},
+	{
+		HTC_CTRL_RSVD_SVC,
+		PIPEDIR_IN,     /* in = DL = target -> host */
+		2,
+	},
+	{
+		HTC_RAW_STREAMS_SVC, /* not currently used */
+		PIPEDIR_OUT,    /* out = UL = host -> target */
+		0,
+	},
+	{
+		HTC_RAW_STREAMS_SVC, /* not currently used */
+		PIPEDIR_IN,     /* in = DL = target -> host */
+		2,
+	},
+	{
+		HTT_DATA_MSG_SVC,
+		PIPEDIR_OUT,    /* out = UL = host -> target */
+		4,
+	},
+	{
+		HTT_DATA_MSG_SVC,
+		PIPEDIR_IN,     /* in = DL = target -> host */
+		1,
+	},
+	{
+		WDI_IPA_TX_SVC,
+		PIPEDIR_OUT,    /* in = DL = target -> host */
+		5,
+	},
+	/* (Additions here) */
+
+	{                       /* Must be last */
+		0,
+		0,
+		0,
+	},
+};
+
+static struct service_to_pipe *target_service_to_ce_map =
+	target_service_to_ce_map_wlan;
+static int target_service_to_ce_map_sz = sizeof(target_service_to_ce_map_wlan);
+
+static struct shadow_reg_cfg *target_shadow_reg_cfg = target_shadow_reg_cfg_map;
+static int shadow_cfg_sz = sizeof(target_shadow_reg_cfg_map);
+
+static struct service_to_pipe target_service_to_ce_map_wlan_epping[] = {
+	{WMI_DATA_VO_SVC, PIPEDIR_OUT, 3,},     /* out = UL = host -> target */
+	{WMI_DATA_VO_SVC, PIPEDIR_IN, 2,},      /* in = DL = target -> host */
+	{WMI_DATA_BK_SVC, PIPEDIR_OUT, 4,},     /* out = UL = host -> target */
+	{WMI_DATA_BK_SVC, PIPEDIR_IN, 1,},      /* in = DL = target -> host */
+	{WMI_DATA_BE_SVC, PIPEDIR_OUT, 3,},     /* out = UL = host -> target */
+	{WMI_DATA_BE_SVC, PIPEDIR_IN, 2,},      /* in = DL = target -> host */
+	{WMI_DATA_VI_SVC, PIPEDIR_OUT, 3,},     /* out = UL = host -> target */
+	{WMI_DATA_VI_SVC, PIPEDIR_IN, 2,},      /* in = DL = target -> host */
+	{WMI_CONTROL_SVC, PIPEDIR_OUT, 3,},     /* out = UL = host -> target */
+	{WMI_CONTROL_SVC, PIPEDIR_IN, 2,},      /* in = DL = target -> host */
+	{HTC_CTRL_RSVD_SVC, PIPEDIR_OUT, 0,},   /* out = UL = host -> target */
+	{HTC_CTRL_RSVD_SVC, PIPEDIR_IN, 2,},    /* in = DL = target -> host */
+	{HTC_RAW_STREAMS_SVC, PIPEDIR_OUT, 0,}, /* out = UL = host -> target */
+	{HTC_RAW_STREAMS_SVC, PIPEDIR_IN, 2,},  /* in = DL = target -> host */
+	{HTT_DATA_MSG_SVC, PIPEDIR_OUT, 4,},    /* out = UL = host -> target */
+	{HTT_DATA_MSG_SVC, PIPEDIR_IN, 1,},     /* in = DL = target -> host */
+	{0, 0, 0,},             /* Must be last */
+};
+
+#ifdef HIF_PCI
+/*
+ * Send an interrupt to the device to wake up the Target CPU
+ * so it has an opportunity to notice any changed state.
+ */
+void hif_wake_target_cpu(struct ol_softc *scn)
+{
+	CDF_STATUS rv;
+	uint32_t core_ctrl;
+
+	rv = hif_diag_read_access(scn,
+				  SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS,
+				  &core_ctrl);
+	CDF_ASSERT(rv == CDF_STATUS_SUCCESS);
+	/* A_INUM_FIRMWARE interrupt to Target CPU */
+	core_ctrl |= CORE_CTRL_CPU_INTR_MASK;
+
+	rv = hif_diag_write_access(scn,
+				   SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS,
+				   core_ctrl);
+	CDF_ASSERT(rv == CDF_STATUS_SUCCESS);
+}
+#endif
+
+static void hif_sleep_entry(void *arg)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)arg;
+	struct ol_softc *scn = hif_state->scn;
+	uint32_t idle_ms;
+	if (scn->recovery)
+		return;
+
+	cdf_spin_lock_irqsave(&hif_state->keep_awake_lock);
+	if (hif_state->verified_awake == false) {
+		idle_ms = cdf_system_ticks_to_msecs(cdf_system_ticks()
+						    - hif_state->sleep_ticks);
+		if (idle_ms >= HIF_MIN_SLEEP_INACTIVITY_TIME_MS) {
+			if (!cdf_atomic_read(&scn->link_suspended)) {
+				soc_wake_reset(scn);
+				hif_state->fake_sleep = false;
+			}
+		} else {
+			cdf_softirq_timer_cancel(&hif_state->sleep_timer);
+			cdf_softirq_timer_start(&hif_state->sleep_timer,
+				    HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS);
+		}
+	} else {
+		cdf_softirq_timer_cancel(&hif_state->sleep_timer);
+		cdf_softirq_timer_start(&hif_state->sleep_timer,
+					HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS);
+	}
+	cdf_spin_unlock_irqrestore(&hif_state->keep_awake_lock);
+}
+#define HIF_HIA_MAX_POLL_LOOP    1000000
+#define HIF_HIA_POLLING_DELAY_MS 10
+
+#ifndef HIF_PCI
+int hif_set_hia(struct ol_softc *scn)
+{
+	return 0;
+}
+#else
+int hif_set_hia(struct ol_softc *scn)
+{
+	CDF_STATUS rv;
+	uint32_t interconnect_targ_addr = 0;
+	uint32_t pcie_state_targ_addr = 0;
+	uint32_t pipe_cfg_targ_addr = 0;
+	uint32_t svc_to_pipe_map = 0;
+	uint32_t pcie_config_flags = 0;
+	uint32_t flag2_value = 0;
+	uint32_t flag2_targ_addr = 0;
+#ifdef QCA_WIFI_3_0
+	uint32_t host_interest_area = 0;
+	uint8_t i;
+#else
+	uint32_t ealloc_value = 0;
+	uint32_t ealloc_targ_addr = 0;
+	uint8_t banks_switched = 1;
+	uint32_t chip_id;
+#endif
+	uint32_t pipe_cfg_addr;
+
+	HIF_TRACE("%s: E", __func__);
+
+	if (IHELIUM_BU || ADRASTEA_BU)
+		return CDF_STATUS_SUCCESS;
+
+#ifdef QCA_WIFI_3_0
+	i = 0;
+	while (i < HIF_HIA_MAX_POLL_LOOP) {
+		host_interest_area = hif_read32_mb(scn->mem +
+						A_SOC_CORE_SCRATCH_0_ADDRESS);
+		if ((host_interest_area & 0x01) == 0) {
+			cdf_mdelay(HIF_HIA_POLLING_DELAY_MS);
+			host_interest_area = 0;
+			i++;
+			if (i > HIF_HIA_MAX_POLL_LOOP && (i % 1000 == 0)) {
+				HIF_ERROR("%s: poll timeout(%d)", __func__, i);
+			}
+		} else {
+			host_interest_area &= (~0x01);
+			hif_write32_mb(scn->mem + 0x113014, 0);
+			break;
+		}
+	}
+
+	if (i >= HIF_HIA_MAX_POLL_LOOP) {
+		HIF_ERROR("%s: hia polling timeout", __func__);
+		return -EIO;
+	}
+
+	if (host_interest_area == 0) {
+		HIF_ERROR("%s: host_interest_area = 0", __func__);
+		return -EIO;
+	}
+
+	interconnect_targ_addr = host_interest_area +
+			offsetof(struct host_interest_area_t,
+			hi_interconnect_state);
+
+	flag2_targ_addr = host_interest_area +
+			offsetof(struct host_interest_area_t, hi_option_flag2);
+
+#else
+	interconnect_targ_addr = hif_hia_item_address(scn->target_type,
+		offsetof(struct host_interest_s, hi_interconnect_state));
+	ealloc_targ_addr = hif_hia_item_address(scn->target_type,
+		offsetof(struct host_interest_s, hi_early_alloc));
+	flag2_targ_addr = hif_hia_item_address(scn->target_type,
+		offsetof(struct host_interest_s, hi_option_flag2));
+#endif
+	/* Supply Target-side CE configuration */
+	rv = hif_diag_read_access(scn, interconnect_targ_addr,
+			  &pcie_state_targ_addr);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: interconnect_targ_addr = 0x%0x, ret = %d",
+			  __func__, interconnect_targ_addr, rv);
+		goto done;
+	}
+	if (pcie_state_targ_addr == 0) {
+		rv = CDF_STATUS_E_FAILURE;
+		HIF_ERROR("%s: pcie state addr is 0", __func__);
+		goto done;
+	}
+	pipe_cfg_addr = pcie_state_targ_addr +
+			  offsetof(struct pcie_state_s,
+			  pipe_cfg_addr);
+	rv = hif_diag_read_access(scn,
+			  pipe_cfg_addr,
+			  &pipe_cfg_targ_addr);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: pipe_cfg_addr = 0x%0x, ret = %d",
+			__func__, pipe_cfg_addr, rv);
+		goto done;
+	}
+	if (pipe_cfg_targ_addr == 0) {
+		rv = CDF_STATUS_E_FAILURE;
+		HIF_ERROR("%s: pipe cfg addr is 0", __func__);
+		goto done;
+	}
+
+	rv = hif_diag_write_mem(scn, pipe_cfg_targ_addr,
+			(uint8_t *) target_ce_config,
+			target_ce_config_sz);
+
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: write pipe cfg (%d)", __func__, rv);
+		goto done;
+	}
+
+	rv = hif_diag_read_access(scn,
+			  pcie_state_targ_addr +
+			  offsetof(struct pcie_state_s,
+			   svc_to_pipe_map),
+			  &svc_to_pipe_map);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: get svc/pipe map (%d)", __func__, rv);
+		goto done;
+	}
+	if (svc_to_pipe_map == 0) {
+		rv = CDF_STATUS_E_FAILURE;
+		HIF_ERROR("%s: svc_to_pipe map is 0", __func__);
+		goto done;
+	}
+
+	rv = hif_diag_write_mem(scn,
+			svc_to_pipe_map,
+			(uint8_t *) target_service_to_ce_map,
+			target_service_to_ce_map_sz);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: write svc/pipe map (%d)", __func__, rv);
+		goto done;
+	}
+
+	rv = hif_diag_read_access(scn,
+			pcie_state_targ_addr +
+			offsetof(struct pcie_state_s,
+			config_flags),
+			&pcie_config_flags);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: get pcie config_flags (%d)", __func__, rv);
+		goto done;
+	}
+#if (CONFIG_PCIE_ENABLE_L1_CLOCK_GATE)
+	pcie_config_flags |= PCIE_CONFIG_FLAG_ENABLE_L1;
+#else
+	pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1;
+#endif /* CONFIG_PCIE_ENABLE_L1_CLOCK_GATE */
+	pcie_config_flags |= PCIE_CONFIG_FLAG_CLK_SWITCH_WAIT;
+#if (CONFIG_PCIE_ENABLE_AXI_CLK_GATE)
+	pcie_config_flags |= PCIE_CONFIG_FLAG_AXI_CLK_GATE;
+#endif
+	rv = hif_diag_write_mem(scn,
+			pcie_state_targ_addr +
+			offsetof(struct pcie_state_s,
+			config_flags),
+			(uint8_t *) &pcie_config_flags,
+			sizeof(pcie_config_flags));
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: write pcie config_flags (%d)", __func__, rv);
+		goto done;
+	}
+
+#ifndef QCA_WIFI_3_0
+	/* configure early allocation */
+	ealloc_targ_addr = hif_hia_item_address(scn->target_type,
+							offsetof(
+							struct host_interest_s,
+							hi_early_alloc));
+
+	rv = hif_diag_read_access(scn, ealloc_targ_addr,
+			&ealloc_value);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: get early alloc val (%d)", __func__, rv);
+		goto done;
+	}
+
+	/* 1 bank is switched to IRAM, except ROME 1.0 */
+	ealloc_value |=
+		((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) &
+		 HI_EARLY_ALLOC_MAGIC_MASK);
+
+	rv = hif_diag_read_access(scn,
+			  CHIP_ID_ADDRESS |
+			  RTC_SOC_BASE_ADDRESS, &chip_id);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: get chip id val (%d)", __func__, rv);
+		goto done;
+	}
+	if (CHIP_ID_VERSION_GET(chip_id) == 0xD) {
+		scn->target_revision =
+			CHIP_ID_REVISION_GET(chip_id);
+		switch (CHIP_ID_REVISION_GET(chip_id)) {
+		case 0x2:       /* ROME 1.3 */
+			/* 2 banks are switched to IRAM */
+			banks_switched = 2;
+			break;
+		case 0x4:       /* ROME 2.1 */
+		case 0x5:       /* ROME 2.2 */
+			banks_switched = 6;
+			break;
+		case 0x8:       /* ROME 3.0 */
+		case 0x9:       /* ROME 3.1 */
+		case 0xA:       /* ROME 3.2 */
+			banks_switched = 9;
+			break;
+		case 0x0:       /* ROME 1.0 */
+		case 0x1:       /* ROME 1.1 */
+		default:
+			/* 3 banks are switched to IRAM */
+			banks_switched = 3;
+			break;
+		}
+	}
+
+	ealloc_value |=
+		((banks_switched << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT)
+		 & HI_EARLY_ALLOC_IRAM_BANKS_MASK);
+
+	rv = hif_diag_write_access(scn,
+				ealloc_targ_addr,
+				ealloc_value);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: set early alloc val (%d)", __func__, rv);
+		goto done;
+	}
+#endif
+
+	/* Tell Target to proceed with initialization */
+	flag2_targ_addr = hif_hia_item_address(scn->target_type,
+						offsetof(
+						struct host_interest_s,
+						hi_option_flag2));
+
+	rv = hif_diag_read_access(scn, flag2_targ_addr,
+			  &flag2_value);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: get option val (%d)", __func__, rv);
+		goto done;
+	}
+
+	flag2_value |= HI_OPTION_EARLY_CFG_DONE;
+	rv = hif_diag_write_access(scn, flag2_targ_addr,
+			   flag2_value);
+	if (rv != CDF_STATUS_SUCCESS) {
+		HIF_ERROR("%s: set option val (%d)", __func__, rv);
+		goto done;
+	}
+
+	hif_wake_target_cpu(scn);
+
+done:
+
+	return rv;
+}
+#endif
+
+/**
+ * hif_wlan_enable(): call the platform driver to enable wlan
+ *
+ * This function passes the con_mode and CE configuration to
+ * platform driver to enable wlan.
+ *
+ * Return: void
+ */
+static int hif_wlan_enable(void)
+{
+	struct icnss_wlan_enable_cfg cfg;
+	enum icnss_driver_mode mode;
+	uint32_t con_mode = cds_get_conparam();
+
+	cfg.num_ce_tgt_cfg = target_ce_config_sz /
+		sizeof(struct CE_pipe_config);
+	cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *)target_ce_config;
+	cfg.num_ce_svc_pipe_cfg = target_service_to_ce_map_sz /
+		sizeof(struct service_to_pipe);
+	cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *)target_service_to_ce_map;
+	cfg.num_shadow_reg_cfg = shadow_cfg_sz / sizeof(struct shadow_reg_cfg);
+	cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *) target_shadow_reg_cfg;
+
+	switch (con_mode) {
+	case CDF_FTM_MODE:
+		mode = ICNSS_FTM;
+		break;
+	case CDF_EPPING_MODE:
+		mode = ICNSS_EPPING;
+		break;
+	default:
+		mode = ICNSS_MISSION;
+		break;
+	}
+	return icnss_wlan_enable(&cfg, mode, QWLAN_VERSIONSTR);
+}
+
+#if ((!defined(QCA_WIFI_3_0_IHELIUM) && !defined(QCA_WIFI_3_0_ADRASTEA)) || defined(CONFIG_ICNSS))
+static inline void cnss_pcie_notify_q6(void)
+{
+	return;
+}
+#endif
+
+/*
+ * Called from PCI layer whenever a new PCI device is probed.
+ * Initializes per-device HIF state and notifies the main
+ * driver that a new HIF device is present.
+ */
+int hif_config_ce(hif_handle_t hif_hdl)
+{
+	struct HIF_CE_state *hif_state;
+	struct HIF_CE_pipe_info *pipe_info;
+	int pipe_num;
+#ifdef ADRASTEA_SHADOW_REGISTERS
+	int i;
+#endif
+	CDF_STATUS rv = CDF_STATUS_SUCCESS;
+	int ret;
+	struct ol_softc *scn = hif_hdl;
+	struct icnss_soc_info soc_info;
+
+	/* if epping is enabled we need to use the epping configuration. */
+	if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) {
+		if (WLAN_IS_EPPING_IRQ(cds_get_conparam()))
+			host_ce_config = host_ce_config_wlan_epping_irq;
+		else
+			host_ce_config = host_ce_config_wlan_epping_poll;
+		target_ce_config = target_ce_config_wlan_epping;
+		target_ce_config_sz = sizeof(target_ce_config_wlan_epping);
+		target_service_to_ce_map =
+		    target_service_to_ce_map_wlan_epping;
+		target_service_to_ce_map_sz =
+			sizeof(target_service_to_ce_map_wlan_epping);
+	}
+
+	ret = hif_wlan_enable();
+
+	if (ret) {
+		HIF_ERROR("%s: hif_wlan_enable error = %d", __func__, ret);
+		return CDF_STATUS_NOT_INITIALIZED;
+	}
+	if (IHELIUM_BU) {
+		cnss_pcie_notify_q6();
+		HIF_TRACE("%s: cnss_pcie_notify_q6 done, notice_send= %d",
+			  __func__, scn->notice_send);
+	}
+
+	scn->notice_send = true;
+
+	cdf_mem_zero(&soc_info, sizeof(soc_info));
+	ret = icnss_get_soc_info(&soc_info);
+	if (ret < 0) {
+		HIF_ERROR("%s: icnss_get_soc_info error = %d", __func__, ret);
+		return CDF_STATUS_NOT_INITIALIZED;
+	}
+
+	hif_state = (struct HIF_CE_state *)cdf_mem_malloc(sizeof(*hif_state));
+	if (!hif_state) {
+		return -ENOMEM;
+	}
+	cdf_mem_zero(hif_state, sizeof(*hif_state));
+
+	hif_state->scn = scn;
+	scn->hif_hdl = hif_state;
+	scn->mem = soc_info.v_addr;
+	scn->mem_pa = soc_info.p_addr;
+	scn->soc_version = soc_info.version;
+
+	cdf_spinlock_init(&hif_state->keep_awake_lock);
+
+	cdf_atomic_init(&hif_state->hif_thread_idle);
+	cdf_atomic_inc(&hif_state->hif_thread_idle);
+
+	hif_state->keep_awake_count = 0;
+
+	hif_state->fake_sleep = false;
+	hif_state->sleep_ticks = 0;
+	cdf_softirq_timer_init(NULL, &hif_state->sleep_timer,
+			       hif_sleep_entry, (void *)hif_state,
+			       CDF_TIMER_TYPE_WAKE_APPS);
+	hif_state->sleep_timer_init = true;
+	hif_state->fw_indicator_address = FW_INDICATOR_ADDRESS;
+#ifdef HIF_PCI
+#if CONFIG_ATH_PCIE_MAX_PERF || CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD
+	/* Force AWAKE forever/till the driver is loaded */
+	if (hif_target_sleep_state_adjust(scn, false, true) < 0)
+		return -EACCES;
+#endif
+#endif
+
+	/* During CE initializtion */
+	scn->ce_count = HOST_CE_COUNT;
+	A_TARGET_ACCESS_LIKELY(scn);
+	for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) {
+		struct CE_attr *attr;
+
+		pipe_info = &hif_state->pipe_info[pipe_num];
+		pipe_info->pipe_num = pipe_num;
+		pipe_info->HIF_CE_state = hif_state;
+		attr = &host_ce_config[pipe_num];
+		pipe_info->ce_hdl = ce_init(scn, pipe_num, attr);
+		CDF_ASSERT(pipe_info->ce_hdl != NULL);
+		if (pipe_info->ce_hdl == NULL) {
+			rv = CDF_STATUS_E_FAILURE;
+			A_TARGET_ACCESS_UNLIKELY(scn);
+			goto err;
+		}
+
+		if (pipe_num == DIAG_CE_ID) {
+			/* Reserve the ultimate CE for
+			 * Diagnostic Window support */
+			hif_state->ce_diag =
+				hif_state->pipe_info[scn->ce_count - 1].ce_hdl;
+			continue;
+		}
+
+		pipe_info->buf_sz = (cdf_size_t) (attr->src_sz_max);
+		cdf_spinlock_init(&pipe_info->recv_bufs_needed_lock);
+		if (attr->dest_nentries > 0) {
+			atomic_set(&pipe_info->recv_bufs_needed,
+				   init_buffer_count(attr->dest_nentries - 1));
+		} else {
+			atomic_set(&pipe_info->recv_bufs_needed, 0);
+		}
+		ce_tasklet_init(hif_state, (1 << pipe_num));
+		ce_register_irq(hif_state, (1 << pipe_num));
+		scn->request_irq_done = true;
+	}
+
+	if (athdiag_procfs_init(scn) != 0) {
+		A_TARGET_ACCESS_UNLIKELY(scn);
+		goto err;
+	}
+	scn->athdiag_procfs_inited = true;
+
+	/*
+	 * Initially, establish CE completion handlers for use with BMI.
+	 * These are overwritten with generic handlers after we exit BMI phase.
+	 */
+	pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_TARG];
+#ifdef HIF_PCI
+	ce_send_cb_register(
+	   pipe_info->ce_hdl, hif_bmi_send_done, pipe_info, 0);
+#ifndef BMI_RSP_POLLING
+	pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_HOST];
+	ce_recv_cb_register(
+	   pipe_info->ce_hdl, hif_bmi_recv_data, pipe_info, 0);
+#endif
+#endif
+	HIF_INFO_MED("%s: ce_init done", __func__);
+
+	rv = hif_set_hia(scn);
+
+	HIF_INFO_MED("%s: hif_set_hia done", __func__);
+
+	A_TARGET_ACCESS_UNLIKELY(scn);
+
+	if (rv != CDF_STATUS_SUCCESS)
+		goto err;
+	else
+		init_tasklet_workers();
+
+	HIF_TRACE("%s: X, ret = %d\n", __func__, rv);
+
+#ifdef ADRASTEA_SHADOW_REGISTERS
+	HIF_ERROR("Using Shadow Registers instead of CE Registers\n");
+	for (i = 0; i < NUM_SHADOW_REGISTERS; i++) {
+		HIF_ERROR("%s Shadow Register%d is mapped to address %x\n",
+			  __func__, i,
+			  (A_TARGET_READ(scn, (SHADOW_ADDRESS(i))) << 2));
+	}
+#endif
+
+
+	return rv != CDF_STATUS_SUCCESS;
+
+err:
+	/* Failure, so clean up */
+	for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) {
+		pipe_info = &hif_state->pipe_info[pipe_num];
+		if (pipe_info->ce_hdl) {
+			ce_unregister_irq(hif_state, (1 << pipe_num));
+			scn->request_irq_done = false;
+			ce_fini(pipe_info->ce_hdl);
+			pipe_info->ce_hdl = NULL;
+			pipe_info->buf_sz = 0;
+		}
+	}
+	if (hif_state->sleep_timer_init) {
+		cdf_softirq_timer_cancel(&hif_state->sleep_timer);
+		cdf_softirq_timer_free(&hif_state->sleep_timer);
+		hif_state->sleep_timer_init = false;
+	}
+	if (scn->hif_hdl) {
+		scn->hif_hdl = NULL;
+		cdf_mem_free(hif_state);
+	}
+	athdiag_procfs_remove();
+	scn->athdiag_procfs_inited = false;
+	HIF_TRACE("%s: X, ret = %d\n", __func__, rv);
+	return CDF_STATUS_SUCCESS != CDF_STATUS_E_FAILURE;
+}
+
+
+
+
+
+
+#ifdef IPA_OFFLOAD
+void hif_ipa_get_ce_resource(struct ol_softc *scn,
+			     uint32_t *ce_sr_base_paddr,
+			     uint32_t *ce_sr_ring_size,
+			     cdf_dma_addr_t *ce_reg_paddr)
+{
+	struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl;
+	struct HIF_CE_pipe_info *pipe_info =
+		&(hif_state->pipe_info[HIF_PCI_IPA_UC_ASSIGNED_CE]);
+	struct CE_handle *ce_hdl = pipe_info->ce_hdl;
+
+	ce_ipa_get_resource(ce_hdl, ce_sr_base_paddr, ce_sr_ring_size,
+			    ce_reg_paddr);
+	return;
+}
+#endif /* IPA_OFFLOAD */
+
+
+#ifdef ADRASTEA_SHADOW_REGISTERS
+
+/*
+	Current shadow register config
+
+	-----------------------------------------------------------
+	Shadow Register      |     CE   |    src/dst write index
+	-----------------------------------------------------------
+		0            |     0    |           src
+		1     No Config - Doesn't point to anything
+		2     No Config - Doesn't point to anything
+		3            |     3    |           src
+		4            |     4    |           src
+		5            |     5    |           src
+		6     No Config - Doesn't point to anything
+		7            |     7    |           src
+		8     No Config - Doesn't point to anything
+		9     No Config - Doesn't point to anything
+		10    No Config - Doesn't point to anything
+		11    No Config - Doesn't point to anything
+	-----------------------------------------------------------
+		12    No Config - Doesn't point to anything
+		13           |     1    |           dst
+		14           |     2    |           dst
+		15    No Config - Doesn't point to anything
+		16    No Config - Doesn't point to anything
+		17    No Config - Doesn't point to anything
+		18    No Config - Doesn't point to anything
+		19           |     7    |           dst
+		20           |     8    |           dst
+		21    No Config - Doesn't point to anything
+		22    No Config - Doesn't point to anything
+		23    No Config - Doesn't point to anything
+	-----------------------------------------------------------
+
+
+	ToDo - Move shadow register config to following in the future
+	This helps free up a block of shadow registers towards the end.
+	Can be used for other purposes
+
+	-----------------------------------------------------------
+	Shadow Register      |     CE   |    src/dst write index
+	-----------------------------------------------------------
+		0            |     0    |           src
+		1            |     3    |           src
+		2            |     4    |           src
+		3            |     5    |           src
+		4            |     7    |           src
+	-----------------------------------------------------------
+		5            |     1    |           dst
+		6            |     2    |           dst
+		7            |     7    |           dst
+		8            |     8    |           dst
+	-----------------------------------------------------------
+		9     No Config - Doesn't point to anything
+		12    No Config - Doesn't point to anything
+		13    No Config - Doesn't point to anything
+		14    No Config - Doesn't point to anything
+		15    No Config - Doesn't point to anything
+		16    No Config - Doesn't point to anything
+		17    No Config - Doesn't point to anything
+		18    No Config - Doesn't point to anything
+		19    No Config - Doesn't point to anything
+		20    No Config - Doesn't point to anything
+		21    No Config - Doesn't point to anything
+		22    No Config - Doesn't point to anything
+		23    No Config - Doesn't point to anything
+	-----------------------------------------------------------
+*/
+
+u32 shadow_sr_wr_ind_addr(struct ol_softc *scn, u32 ctrl_addr)
+{
+	u32 addr = 0;
+
+	switch (COPY_ENGINE_ID(ctrl_addr)) {
+	case 0:
+		addr = SHADOW_VALUE0;
+		break;
+	case 3:
+		addr = SHADOW_VALUE3;
+		break;
+	case 4:
+		addr = SHADOW_VALUE4;
+		break;
+	case 5:
+		addr = SHADOW_VALUE5;
+		break;
+	case 7:
+		addr = SHADOW_VALUE7;
+		break;
+	default:
+		printk("invalid CE ctrl_addr\n");
+		CDF_ASSERT(0);
+
+	}
+	return addr;
+
+}
+
+u32 shadow_dst_wr_ind_addr(struct ol_softc *scn, u32 ctrl_addr)
+{
+	u32 addr = 0;
+
+	switch (COPY_ENGINE_ID(ctrl_addr)) {
+	case 1:
+		addr = SHADOW_VALUE13;
+		break;
+	case 2:
+		addr = SHADOW_VALUE14;
+		break;
+	case 7:
+		addr = SHADOW_VALUE19;
+		break;
+	case 8:
+		addr = SHADOW_VALUE20;
+		break;
+	default:
+		printk("invalid CE ctrl_addr\n");
+		CDF_ASSERT(0);
+	}
+
+	return addr;
+
+}
+#endif
+
+void ce_lro_flush_cb_register(struct ol_softc *scn,
+	 void (handler)(void *), void *data)
+{
+	struct CE_state *ce_state = scn->ce_id_to_state[CE_HTT_T2H_MSG];
+	ce_state->lro_flush_cb = handler;
+	ce_state->lro_data = data;
+}
diff --git a/core/hif/src/ce/ce_main.h b/core/hif/src/ce/ce_main.h
new file mode 100644
index 0000000..570fd41
--- /dev/null
+++ b/core/hif/src/ce/ce_main.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef __CE_H__
+#define __CE_H__
+
+#include "cdf_atomic.h"
+#include "cdf_lock.h"
+#include "hif.h"
+
+#define CE_HTT_T2H_MSG 1
+#define CE_HTT_H2T_MSG 4
+
+/**
+ * enum ce_id_type
+ *
+ * @ce_id_type: Copy engine ID
+ */
+enum ce_id_type {
+	CE_ID_0,
+	CE_ID_1,
+	CE_ID_2,
+	CE_ID_3,
+	CE_ID_4,
+	CE_ID_5,
+	CE_ID_6,
+	CE_ID_7,
+	CE_ID_8,
+	CE_ID_9,
+	CE_ID_10,
+	CE_ID_11,
+	CE_ID_MAX
+};
+struct HIF_CE_completion_state {
+	struct HIF_CE_completion_state *next;
+	int send_or_recv;
+	struct CE_handle *copyeng;
+	void *ce_context;
+	void *transfer_context;
+	cdf_dma_addr_t data;
+	unsigned int nbytes;
+	unsigned int transfer_id;
+	unsigned int flags;
+	uint32_t toeplitz_hash_result;
+};
+
+/* compl_state.send_or_recv */
+#define HIF_CE_COMPLETE_FREE 0
+#define HIF_CE_COMPLETE_SEND 1
+#define HIF_CE_COMPLETE_RECV 2
+
+enum ol_ath_hif_pkt_ecodes {
+	HIF_PIPE_NO_RESOURCE = 0
+};
+
+struct HIF_CE_state;
+#define HIF_CE_COMPLETE_STATE_NUM 18 /* 56 * 18 + 4/8 = 1012/1016 bytes */
+struct HIF_CE_completion_state_list {
+	struct HIF_CE_completion_state_list *next;
+};
+
+/* Per-pipe state. */
+struct HIF_CE_pipe_info {
+	/* Handle of underlying Copy Engine */
+	struct CE_handle *ce_hdl;
+
+	/* Our pipe number; facilitiates use of pipe_info ptrs. */
+	uint8_t pipe_num;
+
+	/* Convenience back pointer to HIF_CE_state. */
+	struct HIF_CE_state *HIF_CE_state;
+
+	/* Instantaneous number of receive buffers that should be posted */
+	atomic_t recv_bufs_needed;
+	cdf_size_t buf_sz;
+	cdf_spinlock_t recv_bufs_needed_lock;
+
+	cdf_spinlock_t completion_freeq_lock;
+	/* Limit the number of outstanding send requests. */
+	int num_sends_allowed;
+	struct HIF_CE_completion_state_list *completion_space_list;
+	struct HIF_CE_completion_state *completion_freeq_head;
+	struct HIF_CE_completion_state *completion_freeq_tail;
+	/* adding three counts for debugging ring buffer errors */
+	uint32_t nbuf_alloc_err_count;
+	uint32_t nbuf_dma_err_count;
+	uint32_t nbuf_ce_enqueue_err_count;
+};
+
+/**
+ * struct ce_tasklet_entry
+ *
+ * @intr_tq: intr_tq
+ * @ce_id: ce_id
+ * @inited: inited
+ * @hif_ce_state: hif_ce_state
+ * @from_irq: from_irq
+ */
+struct ce_tasklet_entry {
+	struct tasklet_struct intr_tq;
+	enum ce_id_type ce_id;
+	bool inited;
+	void *hif_ce_state;
+	bool from_irq;
+};
+
+struct HIF_CE_state {
+	struct ol_softc *scn;
+	bool started;
+	struct ce_tasklet_entry tasklets[CE_COUNT_MAX];
+	cdf_spinlock_t keep_awake_lock;
+	unsigned int keep_awake_count;
+	bool verified_awake;
+	bool fake_sleep;
+	cdf_softirq_timer_t sleep_timer;
+	bool sleep_timer_init;
+	unsigned long sleep_ticks;
+	cdf_spinlock_t completion_pendingq_lock;
+	/* Queue of send/recv completions that need to be processed */
+	struct HIF_CE_completion_state *completion_pendingq_head;
+	struct HIF_CE_completion_state *completion_pendingq_tail;
+	atomic_t fw_event_pending;
+	cdf_atomic_t hif_thread_idle;
+
+	/* wait_queue_head_t service_waitq; */
+	/* struct task_struct *compl_thread; */
+	/* struct completion compl_thread_done; */
+
+	/* Per-pipe state. */
+	struct HIF_CE_pipe_info pipe_info[CE_COUNT_MAX];
+	/* to be activated after BMI_DONE */
+	struct hif_msg_callbacks msg_callbacks_pending;
+	/* current msg callbacks in use */
+	struct hif_msg_callbacks msg_callbacks_current;
+
+	void *claimedContext;
+
+	/* Target address used to signal a pending firmware event */
+	uint32_t fw_indicator_address;
+
+	/* Copy Engine used for Diagnostic Accesses */
+	struct CE_handle *ce_diag;
+};
+#endif /* __CE_H__ */
diff --git a/core/hif/src/ce/ce_reg.h b/core/hif/src/ce/ce_reg.h
new file mode 100644
index 0000000..cb74394
--- /dev/null
+++ b/core/hif/src/ce/ce_reg.h
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef __CE_REG_H__
+#define __CE_REG_H__
+
+#define DST_WR_INDEX_ADDRESS    (scn->target_ce_def->d_DST_WR_INDEX_ADDRESS)
+#define SRC_WATERMARK_ADDRESS   (scn->target_ce_def->d_SRC_WATERMARK_ADDRESS)
+#define SRC_WATERMARK_LOW_MASK  (scn->target_ce_def->d_SRC_WATERMARK_LOW_MASK)
+#define SRC_WATERMARK_HIGH_MASK (scn->target_ce_def->d_SRC_WATERMARK_HIGH_MASK)
+#define DST_WATERMARK_LOW_MASK  (scn->target_ce_def->d_DST_WATERMARK_LOW_MASK)
+#define DST_WATERMARK_HIGH_MASK (scn->target_ce_def->d_DST_WATERMARK_HIGH_MASK)
+#define CURRENT_SRRI_ADDRESS    (scn->target_ce_def->d_CURRENT_SRRI_ADDRESS)
+#define CURRENT_DRRI_ADDRESS    (scn->target_ce_def->d_CURRENT_DRRI_ADDRESS)
+
+#define SHADOW_VALUE0           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_0)
+#define SHADOW_VALUE1           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_1)
+#define SHADOW_VALUE2           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_2)
+#define SHADOW_VALUE3           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_3)
+#define SHADOW_VALUE4           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_4)
+#define SHADOW_VALUE5           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_5)
+#define SHADOW_VALUE6           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_6)
+#define SHADOW_VALUE7           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_7)
+#define SHADOW_VALUE8           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_8)
+#define SHADOW_VALUE9           (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_9)
+#define SHADOW_VALUE10          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_10)
+#define SHADOW_VALUE11          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_11)
+#define SHADOW_VALUE12          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_12)
+#define SHADOW_VALUE13          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_13)
+#define SHADOW_VALUE14          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_14)
+#define SHADOW_VALUE15          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_15)
+#define SHADOW_VALUE16          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_16)
+#define SHADOW_VALUE17          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_17)
+#define SHADOW_VALUE18          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_18)
+#define SHADOW_VALUE19          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_19)
+#define SHADOW_VALUE20          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_20)
+#define SHADOW_VALUE21          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_21)
+#define SHADOW_VALUE22          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_22)
+#define SHADOW_VALUE23          (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_23)
+#define SHADOW_ADDRESS0         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_0)
+#define SHADOW_ADDRESS1         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_1)
+#define SHADOW_ADDRESS2         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_2)
+#define SHADOW_ADDRESS3         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_3)
+#define SHADOW_ADDRESS4         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_4)
+#define SHADOW_ADDRESS5         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_5)
+#define SHADOW_ADDRESS6         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_6)
+#define SHADOW_ADDRESS7         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_7)
+#define SHADOW_ADDRESS8         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_8)
+#define SHADOW_ADDRESS9         (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_9)
+#define SHADOW_ADDRESS10        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_10)
+#define SHADOW_ADDRESS11        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_11)
+#define SHADOW_ADDRESS12        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_12)
+#define SHADOW_ADDRESS13        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_13)
+#define SHADOW_ADDRESS14        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_14)
+#define SHADOW_ADDRESS15        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_15)
+#define SHADOW_ADDRESS16        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_16)
+#define SHADOW_ADDRESS17        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_17)
+#define SHADOW_ADDRESS18        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_18)
+#define SHADOW_ADDRESS19        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_19)
+#define SHADOW_ADDRESS20        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_20)
+#define SHADOW_ADDRESS21        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_21)
+#define SHADOW_ADDRESS22        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_22)
+#define SHADOW_ADDRESS23        (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_23)
+
+#define SHADOW_ADDRESS(i) (SHADOW_ADDRESS0 + i*(SHADOW_ADDRESS1-SHADOW_ADDRESS0))
+
+#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK \
+	(scn->target_ce_def->d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK)
+#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK \
+	(scn->target_ce_def->d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK)
+#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK \
+	(scn->target_ce_def->d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK)
+#define HOST_IS_DST_RING_LOW_WATERMARK_MASK \
+	(scn->target_ce_def->d_HOST_IS_DST_RING_LOW_WATERMARK_MASK)
+#define MISC_IS_ADDRESS         (scn->target_ce_def->d_MISC_IS_ADDRESS)
+#define HOST_IS_COPY_COMPLETE_MASK \
+	(scn->target_ce_def->d_HOST_IS_COPY_COMPLETE_MASK)
+#define CE_WRAPPER_BASE_ADDRESS (scn->target_ce_def->d_CE_WRAPPER_BASE_ADDRESS)
+#define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS \
+	(scn->target_ce_def->d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)
+#define CE_WRAPPER_INDEX_BASE_LOW \
+	(scn->target_ce_def->d_CE_WRAPPER_INDEX_BASE_LOW)
+#define CE_WRAPPER_INDEX_BASE_HIGH \
+	(scn->target_ce_def->d_CE_WRAPPER_INDEX_BASE_HIGH)
+#define HOST_IE_COPY_COMPLETE_MASK \
+	(scn->target_ce_def->d_HOST_IE_COPY_COMPLETE_MASK)
+#define SR_BA_ADDRESS             (scn->target_ce_def->d_SR_BA_ADDRESS)
+#define SR_BA_ADDRESS_HIGH        (scn->target_ce_def->d_SR_BA_ADDRESS_HIGH)
+#define SR_SIZE_ADDRESS           (scn->target_ce_def->d_SR_SIZE_ADDRESS)
+#define CE_CTRL1_ADDRESS          (scn->target_ce_def->d_CE_CTRL1_ADDRESS)
+#define CE_CTRL1_DMAX_LENGTH_MASK \
+	(scn->target_ce_def->d_CE_CTRL1_DMAX_LENGTH_MASK)
+#define DR_BA_ADDRESS             (scn->target_ce_def->d_DR_BA_ADDRESS)
+#define DR_BA_ADDRESS_HIGH        (scn->target_ce_def->d_DR_BA_ADDRESS_HIGH)
+#define DR_SIZE_ADDRESS           (scn->target_ce_def->d_DR_SIZE_ADDRESS)
+#define CE_CMD_REGISTER           (scn->target_ce_def->d_CE_CMD_REGISTER)
+#define CE_MSI_ADDRESS            (scn->target_ce_def->d_CE_MSI_ADDRESS)
+#define CE_MSI_ADDRESS_HIGH       (scn->target_ce_def->d_CE_MSI_ADDRESS_HIGH)
+#define CE_MSI_DATA               (scn->target_ce_def->d_CE_MSI_DATA)
+#define CE_MSI_ENABLE_BIT         (scn->target_ce_def->d_CE_MSI_ENABLE_BIT)
+#define MISC_IE_ADDRESS           (scn->target_ce_def->d_MISC_IE_ADDRESS)
+#define MISC_IS_AXI_ERR_MASK      (scn->target_ce_def->d_MISC_IS_AXI_ERR_MASK)
+#define MISC_IS_DST_ADDR_ERR_MASK \
+	(scn->target_ce_def->d_MISC_IS_DST_ADDR_ERR_MASK)
+#define MISC_IS_SRC_LEN_ERR_MASK \
+	(scn->target_ce_def->d_MISC_IS_SRC_LEN_ERR_MASK)
+#define MISC_IS_DST_MAX_LEN_VIO_MASK \
+	(scn->target_ce_def->d_MISC_IS_DST_MAX_LEN_VIO_MASK)
+#define MISC_IS_DST_RING_OVERFLOW_MASK \
+	(scn->target_ce_def->d_MISC_IS_DST_RING_OVERFLOW_MASK)
+#define MISC_IS_SRC_RING_OVERFLOW_MASK \
+	(scn->target_ce_def->d_MISC_IS_SRC_RING_OVERFLOW_MASK)
+#define SRC_WATERMARK_LOW_LSB     (scn->target_ce_def->d_SRC_WATERMARK_LOW_LSB)
+#define SRC_WATERMARK_HIGH_LSB    (scn->target_ce_def->d_SRC_WATERMARK_HIGH_LSB)
+#define DST_WATERMARK_LOW_LSB     (scn->target_ce_def->d_DST_WATERMARK_LOW_LSB)
+#define DST_WATERMARK_HIGH_LSB    (scn->target_ce_def->d_DST_WATERMARK_HIGH_LSB)
+#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \
+	(scn->target_ce_def->d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK)
+#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB  \
+	(scn->target_ce_def->d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB)
+#define CE_CTRL1_DMAX_LENGTH_LSB  (scn->target_ce_def->d_CE_CTRL1_DMAX_LENGTH_LSB)
+#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK \
+	(scn->target_ce_def->d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK)
+#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK \
+	(scn->target_ce_def->d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK)
+#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB \
+	(scn->target_ce_def->d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB)
+#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB \
+	(scn->target_ce_def->d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB)
+#define WLAN_DEBUG_INPUT_SEL_OFFSET \
+	(scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_OFFSET)
+#define WLAN_DEBUG_INPUT_SEL_SRC_MSB \
+	(scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_MSB)
+#define WLAN_DEBUG_INPUT_SEL_SRC_LSB \
+	(scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_LSB)
+#define WLAN_DEBUG_INPUT_SEL_SRC_MASK \
+	(scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_MASK)
+#define WLAN_DEBUG_CONTROL_OFFSET  (scn->targetdef->d_WLAN_DEBUG_CONTROL_OFFSET)
+#define WLAN_DEBUG_CONTROL_ENABLE_MSB \
+	(scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_MSB)
+#define WLAN_DEBUG_CONTROL_ENABLE_LSB \
+	(scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_LSB)
+#define WLAN_DEBUG_CONTROL_ENABLE_MASK \
+	(scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_MASK)
+#define WLAN_DEBUG_OUT_OFFSET    (scn->targetdef->d_WLAN_DEBUG_OUT_OFFSET)
+#define WLAN_DEBUG_OUT_DATA_MSB  (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_MSB)
+#define WLAN_DEBUG_OUT_DATA_LSB  (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_LSB)
+#define WLAN_DEBUG_OUT_DATA_MASK (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_MASK)
+#define AMBA_DEBUG_BUS_OFFSET    (scn->targetdef->d_AMBA_DEBUG_BUS_OFFSET)
+#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB \
+	(scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB)
+#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB \
+	(scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB)
+#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK \
+	(scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK)
+#define AMBA_DEBUG_BUS_SEL_MSB    (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_MSB)
+#define AMBA_DEBUG_BUS_SEL_LSB    (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_LSB)
+#define AMBA_DEBUG_BUS_SEL_MASK   (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_MASK)
+#define CE_WRAPPER_DEBUG_OFFSET   (scn->target_ce_def->d_CE_WRAPPER_DEBUG_OFFSET)
+#define CE_WRAPPER_DEBUG_SEL_MSB  (scn->target_ce_def->d_CE_WRAPPER_DEBUG_SEL_MSB)
+#define CE_WRAPPER_DEBUG_SEL_LSB  (scn->target_ce_def->d_CE_WRAPPER_DEBUG_SEL_LSB)
+#define CE_WRAPPER_DEBUG_SEL_MASK (scn->target_ce_def->d_CE_WRAPPER_DEBUG_SEL_MASK)
+#define CE_DEBUG_OFFSET           (scn->target_ce_def->d_CE_DEBUG_OFFSET)
+#define CE_DEBUG_SEL_MSB          (scn->target_ce_def->d_CE_DEBUG_SEL_MSB)
+#define CE_DEBUG_SEL_LSB          (scn->target_ce_def->d_CE_DEBUG_SEL_LSB)
+#define CE_DEBUG_SEL_MASK         (scn->target_ce_def->d_CE_DEBUG_SEL_MASK)
+#define HOST_IE_ADDRESS           (scn->target_ce_def->d_HOST_IE_ADDRESS)
+#define HOST_IS_ADDRESS           (scn->target_ce_def->d_HOST_IS_ADDRESS)
+
+#define SRC_WATERMARK_LOW_SET(x) \
+	(((x) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK)
+#define SRC_WATERMARK_HIGH_SET(x) \
+	(((x) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK)
+#define DST_WATERMARK_LOW_SET(x) \
+	(((x) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK)
+#define DST_WATERMARK_HIGH_SET(x) \
+	(((x) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK)
+#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) \
+	(((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \
+		CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB)
+#define CE_CTRL1_DMAX_LENGTH_SET(x) \
+	(((x) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK)
+#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \
+	(((x) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \
+		CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK)
+#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \
+	(((x) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \
+		CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK)
+#define WLAN_DEBUG_INPUT_SEL_SRC_GET(x) \
+	(((x) & WLAN_DEBUG_INPUT_SEL_SRC_MASK) >> \
+		WLAN_DEBUG_INPUT_SEL_SRC_LSB)
+#define WLAN_DEBUG_INPUT_SEL_SRC_SET(x) \
+	(((x) << WLAN_DEBUG_INPUT_SEL_SRC_LSB) & \
+		WLAN_DEBUG_INPUT_SEL_SRC_MASK)
+#define WLAN_DEBUG_CONTROL_ENABLE_GET(x) \
+	(((x) & WLAN_DEBUG_CONTROL_ENABLE_MASK) >> \
+		WLAN_DEBUG_CONTROL_ENABLE_LSB)
+#define WLAN_DEBUG_CONTROL_ENABLE_SET(x) \
+	(((x) << WLAN_DEBUG_CONTROL_ENABLE_LSB) & \
+		WLAN_DEBUG_CONTROL_ENABLE_MASK)
+#define WLAN_DEBUG_OUT_DATA_GET(x) \
+	(((x) & WLAN_DEBUG_OUT_DATA_MASK) >> WLAN_DEBUG_OUT_DATA_LSB)
+#define WLAN_DEBUG_OUT_DATA_SET(x) \
+	(((x) << WLAN_DEBUG_OUT_DATA_LSB) & WLAN_DEBUG_OUT_DATA_MASK)
+#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_GET(x) \
+	(((x) & AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) >> \
+		AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB)
+#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_SET(x) \
+	(((x) << AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) & \
+		AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK)
+#define AMBA_DEBUG_BUS_SEL_GET(x) \
+	(((x) & AMBA_DEBUG_BUS_SEL_MASK) >> AMBA_DEBUG_BUS_SEL_LSB)
+#define AMBA_DEBUG_BUS_SEL_SET(x) \
+	(((x) << AMBA_DEBUG_BUS_SEL_LSB) & AMBA_DEBUG_BUS_SEL_MASK)
+#define CE_WRAPPER_DEBUG_SEL_GET(x) \
+	(((x) & CE_WRAPPER_DEBUG_SEL_MASK) >> CE_WRAPPER_DEBUG_SEL_LSB)
+#define CE_WRAPPER_DEBUG_SEL_SET(x) \
+	(((x) << CE_WRAPPER_DEBUG_SEL_LSB) & CE_WRAPPER_DEBUG_SEL_MASK)
+#define CE_DEBUG_SEL_GET(x) (((x) & CE_DEBUG_SEL_MASK) >> CE_DEBUG_SEL_LSB)
+#define CE_DEBUG_SEL_SET(x) (((x) << CE_DEBUG_SEL_LSB) & CE_DEBUG_SEL_MASK)
+
+#define CE_SRC_RING_READ_IDX_GET(scn, CE_ctrl_addr) \
+	A_TARGET_READ(scn, (CE_ctrl_addr) + CURRENT_SRRI_ADDRESS)
+
+#define CE_SRC_RING_BASE_ADDR_SET(scn, CE_ctrl_addr, addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_BA_ADDRESS, (addr))
+
+#define CE_SRC_RING_BASE_ADDR_HIGH_SET(scn, CE_ctrl_addr, addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_BA_ADDRESS_HIGH, (addr))
+
+#define CE_SRC_RING_BASE_ADDR_HIGH_GET(scn, CE_ctrl_addr) \
+	A_TARGET_READ(scn, (CE_ctrl_addr) + SR_BA_ADDRESS_HIGH)
+
+#define CE_SRC_RING_SZ_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_SIZE_ADDRESS, (n))
+
+#define CE_SRC_RING_DMAX_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, \
+	   (A_TARGET_READ(scn, (CE_ctrl_addr) + \
+	   CE_CTRL1_ADDRESS) & ~CE_CTRL1_DMAX_LENGTH_MASK) | \
+	   CE_CTRL1_DMAX_LENGTH_SET(n))
+
+#define CE_CMD_REGISTER_GET(scn, CE_ctrl_addr) \
+	A_TARGET_READ(scn, (CE_ctrl_addr) + CE_CMD_REGISTER)
+
+#define CE_CMD_REGISTER_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CMD_REGISTER, n)
+
+#define CE_MSI_ADDR_LOW_SET(scn, CE_ctrl_addr, addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_MSI_ADDRESS, (addr))
+
+#define CE_MSI_ADDR_HIGH_SET(scn, CE_ctrl_addr, addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_MSI_ADDRESS_HIGH, (addr))
+
+#define CE_MSI_DATA_SET(scn, CE_ctrl_addr, data) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_MSI_DATA, (data))
+
+#define CE_CTRL_REGISTER1_SET(scn, CE_ctrl_addr, val) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, val)
+
+#define CE_CTRL_REGISTER1_GET(scn, CE_ctrl_addr) \
+	A_TARGET_READ(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS)
+
+#define CE_SRC_RING_BYTE_SWAP_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, \
+		       (A_TARGET_READ((targid), \
+		       (CE_ctrl_addr) + CE_CTRL1_ADDRESS) \
+		       & ~CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) | \
+		       CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(n))
+
+#define CE_DEST_RING_BYTE_SWAP_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr)+CE_CTRL1_ADDRESS, \
+		       (A_TARGET_READ((targid), \
+		       (CE_ctrl_addr) + CE_CTRL1_ADDRESS) \
+		       & ~CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) | \
+		       CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(n))
+
+#define CE_DEST_RING_READ_IDX_GET(scn, CE_ctrl_addr)	\
+	A_TARGET_READ(scn, (CE_ctrl_addr) + CURRENT_DRRI_ADDRESS)
+
+#define CE_DEST_RING_BASE_ADDR_SET(scn, CE_ctrl_addr, addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + DR_BA_ADDRESS, (addr))
+
+#define CE_DEST_RING_BASE_ADDR_HIGH_SET(scn, CE_ctrl_addr, addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + DR_BA_ADDRESS_HIGH, (addr))
+
+#define CE_DEST_RING_BASE_ADDR_HIGH_GET(scn, CE_ctrl_addr) \
+	A_TARGET_READ(scn, (CE_ctrl_addr) + DR_BA_ADDRESS_HIGH)
+
+#define CE_DEST_RING_SZ_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + DR_SIZE_ADDRESS, (n))
+
+#define CE_SRC_RING_HIGHMARK_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS, \
+		       (A_TARGET_READ(scn, \
+		       (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS) \
+		       & ~SRC_WATERMARK_HIGH_MASK) | \
+		       SRC_WATERMARK_HIGH_SET(n))
+
+#define CE_SRC_RING_LOWMARK_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS, \
+		       (A_TARGET_READ(scn, \
+		       (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS) \
+		       & ~SRC_WATERMARK_LOW_MASK) | \
+		       SRC_WATERMARK_LOW_SET(n))
+
+#define CE_DEST_RING_HIGHMARK_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + DST_WATERMARK_ADDRESS, \
+		       (A_TARGET_READ(scn, \
+		       (CE_ctrl_addr) + DST_WATERMARK_ADDRESS) \
+		       & ~DST_WATERMARK_HIGH_MASK) | \
+		       DST_WATERMARK_HIGH_SET(n))
+
+#define CE_DEST_RING_LOWMARK_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + DST_WATERMARK_ADDRESS, \
+		       (A_TARGET_READ(scn, \
+		       (CE_ctrl_addr) + DST_WATERMARK_ADDRESS) \
+		       & ~DST_WATERMARK_LOW_MASK) | \
+		       DST_WATERMARK_LOW_SET(n))
+
+#define CE_COPY_COMPLETE_INTR_ENABLE(scn, CE_ctrl_addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \
+		       A_TARGET_READ(scn, \
+		       (CE_ctrl_addr) + HOST_IE_ADDRESS) | \
+		       HOST_IE_COPY_COMPLETE_MASK)
+
+#define CE_COPY_COMPLETE_INTR_DISABLE(scn, CE_ctrl_addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \
+		       A_TARGET_READ(scn, \
+		       (CE_ctrl_addr) + HOST_IE_ADDRESS) \
+		       & ~HOST_IE_COPY_COMPLETE_MASK)
+
+#define CE_BASE_ADDRESS(CE_id) \
+	CE0_BASE_ADDRESS + ((CE1_BASE_ADDRESS - \
+	CE0_BASE_ADDRESS)*(CE_id))
+
+#define CE_WATERMARK_INTR_ENABLE(scn, CE_ctrl_addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \
+		       A_TARGET_READ(scn, \
+		       (CE_ctrl_addr) + HOST_IE_ADDRESS) | \
+		       CE_WATERMARK_MASK)
+
+#define CE_WATERMARK_INTR_DISABLE(scn, CE_ctrl_addr)	\
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \
+		       A_TARGET_READ(scn, \
+		       (CE_ctrl_addr) + HOST_IE_ADDRESS) \
+		       & ~CE_WATERMARK_MASK)
+
+#define CE_ERROR_INTR_ENABLE(scn, CE_ctrl_addr) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + MISC_IE_ADDRESS, \
+		       A_TARGET_READ(scn, \
+		       (CE_ctrl_addr) + MISC_IE_ADDRESS) | CE_ERROR_MASK)
+
+#define CE_MISC_INT_STATUS_GET(scn, CE_ctrl_addr) \
+	A_TARGET_READ(scn, (CE_ctrl_addr) + MISC_IS_ADDRESS)
+
+#define CE_ENGINE_INT_STATUS_GET(scn, CE_ctrl_addr) \
+	A_TARGET_READ(scn, (CE_ctrl_addr) + HOST_IS_ADDRESS)
+
+#define CE_ENGINE_INT_STATUS_CLEAR(scn, CE_ctrl_addr, mask) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IS_ADDRESS, (mask))
+
+#define CE_WRAPPER_INDEX_BASE_LOW_SET(scn, n) \
+	A_TARGET_WRITE(scn, \
+	   CE_WRAPPER_INDEX_BASE_LOW + CE_WRAPPER_BASE_ADDRESS, n)
+
+#define CE_WRAPPER_INDEX_BASE_HIGH_SET(scn, n) \
+	A_TARGET_WRITE(scn, \
+	   CE_WRAPPER_INDEX_BASE_HIGH + CE_WRAPPER_BASE_ADDRESS, n)
+
+#define CE_WATERMARK_MASK (HOST_IS_SRC_RING_LOW_WATERMARK_MASK  | \
+			   HOST_IS_SRC_RING_HIGH_WATERMARK_MASK | \
+			   HOST_IS_DST_RING_LOW_WATERMARK_MASK  | \
+			   HOST_IS_DST_RING_HIGH_WATERMARK_MASK)
+
+#define CE_ERROR_MASK     (MISC_IS_AXI_ERR_MASK           | \
+			   MISC_IS_DST_ADDR_ERR_MASK      | \
+			   MISC_IS_SRC_LEN_ERR_MASK       | \
+			   MISC_IS_DST_MAX_LEN_VIO_MASK   | \
+			   MISC_IS_DST_RING_OVERFLOW_MASK | \
+			   MISC_IS_SRC_RING_OVERFLOW_MASK)
+
+#define CE_SRC_RING_TO_DESC(baddr, idx) \
+	(&(((struct CE_src_desc *)baddr)[idx]))
+#define CE_DEST_RING_TO_DESC(baddr, idx) \
+	(&(((struct CE_dest_desc *)baddr)[idx]))
+
+/* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */
+#define CE_RING_DELTA(nentries_mask, fromidx, toidx) \
+	(((int)(toidx)-(int)(fromidx)) & (nentries_mask))
+
+#define CE_RING_IDX_INCR(nentries_mask, idx) \
+	(((idx) + 1) & (nentries_mask))
+
+#define CE_RING_IDX_ADD(nentries_mask, idx, num) \
+	(((idx) + (num)) & (nentries_mask))
+
+#define CE_INTERRUPT_SUMMARY(scn) \
+	CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( \
+		A_TARGET_READ(scn, CE_WRAPPER_BASE_ADDRESS + \
+		CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS))
+
+/*Macro to increment CE packet errors*/
+#define OL_ATH_CE_PKT_ERROR_COUNT_INCR(_scn, _ce_ecode) \
+	do { if (_ce_ecode == CE_RING_DELTA_FAIL) \
+			(_scn->pkt_stats.ce_ring_delta_fail_count) \
+			+= 1; } while (0)
+
+/* Given a Copy Engine's ID, determine the interrupt number for that
+ * copy engine's interrupts.
+ */
+#define CE_ID_TO_INUM(id) (A_INUM_CE0_COPY_COMP_BASE + (id))
+#define CE_INUM_TO_ID(inum) ((inum) - A_INUM_CE0_COPY_COMP_BASE)
+#define CE0_BASE_ADDRESS         (scn->target_ce_def->d_CE0_BASE_ADDRESS)
+#define CE1_BASE_ADDRESS         (scn->target_ce_def->d_CE1_BASE_ADDRESS)
+
+#ifdef ADRASTEA_SHADOW_REGISTERS
+
+#define NUM_SHADOW_REGISTERS 24
+
+#define COPY_ENGINE_ID(COPY_ENGINE_BASE_ADDRESS) ((COPY_ENGINE_BASE_ADDRESS \
+		- CE0_BASE_ADDRESS)/(CE1_BASE_ADDRESS - CE0_BASE_ADDRESS))
+
+u32 shadow_sr_wr_ind_addr(struct ol_softc *scn, u32 ctrl_addr);
+u32 shadow_dst_wr_ind_addr(struct ol_softc *scn, u32 ctrl_addr);
+#define CE_SRC_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, shadow_sr_wr_ind_addr(scn, CE_ctrl_addr), n)
+
+#define CE_SRC_RING_WRITE_IDX_GET(scn, CE_ctrl_addr)  \
+	A_TARGET_READ(scn, shadow_sr_wr_ind_addr(scn, CE_ctrl_addr))
+
+#define CE_DEST_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, shadow_dst_wr_ind_addr(scn, CE_ctrl_addr), n)
+
+#define CE_DEST_RING_WRITE_IDX_GET(scn, CE_ctrl_addr) \
+	A_TARGET_READ(scn, shadow_dst_wr_ind_addr(scn, CE_ctrl_addr))
+
+#else
+
+#define CE_SRC_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_WR_INDEX_ADDRESS, (n))
+
+#define CE_SRC_RING_WRITE_IDX_GET(scn, CE_ctrl_addr)	\
+	A_TARGET_READ(scn, (CE_ctrl_addr) + SR_WR_INDEX_ADDRESS)
+
+#define CE_DEST_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \
+	A_TARGET_WRITE(scn, (CE_ctrl_addr) + DST_WR_INDEX_ADDRESS, (n))
+
+#define CE_DEST_RING_WRITE_IDX_GET(scn, CE_ctrl_addr) \
+	A_TARGET_READ(scn, (CE_ctrl_addr) + DST_WR_INDEX_ADDRESS)
+
+#endif
+
+#endif /* __CE_REG_H__ */
diff --git a/core/hif/src/ce/ce_service.c b/core/hif/src/ce/ce_service.c
new file mode 100644
index 0000000..d27ca6b
--- /dev/null
+++ b/core/hif/src/ce/ce_service.c
@@ -0,0 +1,1678 @@
+/*
+ * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#include <osdep.h>
+#include "a_types.h"
+#include <athdefs.h>
+#include "osapi_linux.h"
+#include "hif.h"
+#include "hif_io32.h"
+#include "ce_api.h"
+#include "ce_main.h"
+#include "ce_internal.h"
+#include "ce_reg.h"
+#include "cdf_lock.h"
+#include "regtable.h"
+#include <cds_get_bin.h>
+#include "epping_main.h"
+#include "hif_main.h"
+#include "hif_debug.h"
+
+#ifdef IPA_OFFLOAD
+#ifdef QCA_WIFI_3_0
+#define CE_IPA_RING_INIT(ce_desc)                       \
+	do {                                            \
+		ce_desc->gather = 0;                    \
+		ce_desc->enable_11h = 0;                \
+		ce_desc->meta_data_low = 0;             \
+		ce_desc->packet_result_offset = 64;     \
+		ce_desc->toeplitz_hash_enable = 0;      \
+		ce_desc->addr_y_search_disable = 0;     \
+		ce_desc->addr_x_search_disable = 0;     \
+		ce_desc->misc_int_disable = 0;          \
+		ce_desc->target_int_disable = 0;        \
+		ce_desc->host_int_disable = 0;          \
+		ce_desc->dest_byte_swap = 0;            \
+		ce_desc->byte_swap = 0;                 \
+		ce_desc->type = 2;                      \
+		ce_desc->tx_classify = 1;               \
+		ce_desc->buffer_addr_hi = 0;            \
+		ce_desc->meta_data = 0;                 \
+		ce_desc->nbytes = 128;                  \
+	} while (0)
+#else
+#define CE_IPA_RING_INIT(ce_desc)                       \
+	do {                                            \
+		ce_desc->byte_swap = 0;                 \
+		ce_desc->nbytes = 60;                   \
+		ce_desc->gather = 0;                    \
+	} while (0)
+#endif /* QCA_WIFI_3_0 */
+#endif /* IPA_OFFLOAD */
+
+static int war1_allow_sleep;
+/* io32 write workaround */
+static int hif_ce_war1;
+
+/*
+ * Support for Copy Engine hardware, which is mainly used for
+ * communication between Host and Target over a PCIe interconnect.
+ */
+
+/*
+ * A single CopyEngine (CE) comprises two "rings":
+ *   a source ring
+ *   a destination ring
+ *
+ * Each ring consists of a number of descriptors which specify
+ * an address, length, and meta-data.
+ *
+ * Typically, one side of the PCIe interconnect (Host or Target)
+ * controls one ring and the other side controls the other ring.
+ * The source side chooses when to initiate a transfer and it
+ * chooses what to send (buffer address, length). The destination
+ * side keeps a supply of "anonymous receive buffers" available and
+ * it handles incoming data as it arrives (when the destination
+ * recieves an interrupt).
+ *
+ * The sender may send a simple buffer (address/length) or it may
+ * send a small list of buffers.  When a small list is sent, hardware
+ * "gathers" these and they end up in a single destination buffer
+ * with a single interrupt.
+ *
+ * There are several "contexts" managed by this layer -- more, it
+ * may seem -- than should be needed. These are provided mainly for
+ * maximum flexibility and especially to facilitate a simpler HIF
+ * implementation. There are per-CopyEngine recv, send, and watermark
+ * contexts. These are supplied by the caller when a recv, send,
+ * or watermark handler is established and they are echoed back to
+ * the caller when the respective callbacks are invoked. There is
+ * also a per-transfer context supplied by the caller when a buffer
+ * (or sendlist) is sent and when a buffer is enqueued for recv.
+ * These per-transfer contexts are echoed back to the caller when
+ * the buffer is sent/received.
+ * Target TX harsh result toeplitz_hash_result
+ */
+
+/*
+ * Guts of ce_send, used by both ce_send and ce_sendlist_send.
+ * The caller takes responsibility for any needed locking.
+ */
+int
+ce_completed_send_next_nolock(struct CE_state *CE_state,
+			      void **per_CE_contextp,
+			      void **per_transfer_contextp,
+			      cdf_dma_addr_t *bufferp,
+			      unsigned int *nbytesp,
+			      unsigned int *transfer_idp,
+			      unsigned int *sw_idx, unsigned int *hw_idx,
+			      uint32_t *toeplitz_hash_result);
+
+void war_ce_src_ring_write_idx_set(struct ol_softc *scn,
+				   u32 ctrl_addr, unsigned int write_index)
+{
+	if (hif_ce_war1) {
+		void __iomem *indicator_addr;
+
+		indicator_addr = scn->mem + ctrl_addr + DST_WATERMARK_ADDRESS;
+
+		if (!war1_allow_sleep
+		    && ctrl_addr == CE_BASE_ADDRESS(CDC_WAR_DATA_CE)) {
+			hif_write32_mb(indicator_addr,
+				      (CDC_WAR_MAGIC_STR | write_index));
+		} else {
+			unsigned long irq_flags;
+			local_irq_save(irq_flags);
+			hif_write32_mb(indicator_addr, 1);
+
+			/*
+			 * PCIE write waits for ACK in IPQ8K, there is no
+			 * need to read back value.
+			 */
+			(void)hif_read32_mb(indicator_addr);
+			(void)hif_read32_mb(indicator_addr); /* conservative */
+
+			CE_SRC_RING_WRITE_IDX_SET(scn,
+						  ctrl_addr, write_index);
+
+			hif_write32_mb(indicator_addr, 0);
+			local_irq_restore(irq_flags);
+		}
+	} else
+		CE_SRC_RING_WRITE_IDX_SET(scn, ctrl_addr, write_index);
+}
+
+int
+ce_send_nolock(struct CE_handle *copyeng,
+			   void *per_transfer_context,
+			   cdf_dma_addr_t buffer,
+			   uint32_t nbytes,
+			   uint32_t transfer_id,
+			   uint32_t flags,
+			   uint32_t user_flags)
+{
+	int status;
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	struct CE_ring_state *src_ring = CE_state->src_ring;
+	uint32_t ctrl_addr = CE_state->ctrl_addr;
+	unsigned int nentries_mask = src_ring->nentries_mask;
+	unsigned int sw_index = src_ring->sw_index;
+	unsigned int write_index = src_ring->write_index;
+	uint64_t dma_addr = buffer;
+	struct ol_softc *scn = CE_state->scn;
+
+	A_TARGET_ACCESS_BEGIN_RET(scn);
+	if (unlikely(CE_RING_DELTA(nentries_mask,
+				write_index, sw_index - 1) <= 0)) {
+		OL_ATH_CE_PKT_ERROR_COUNT_INCR(scn, CE_RING_DELTA_FAIL);
+		status = CDF_STATUS_E_FAILURE;
+		A_TARGET_ACCESS_END_RET(scn);
+		return status;
+	}
+	{
+		struct CE_src_desc *src_ring_base =
+			(struct CE_src_desc *)src_ring->base_addr_owner_space;
+		struct CE_src_desc *shadow_base =
+			(struct CE_src_desc *)src_ring->shadow_base;
+		struct CE_src_desc *src_desc =
+			CE_SRC_RING_TO_DESC(src_ring_base, write_index);
+		struct CE_src_desc *shadow_src_desc =
+			CE_SRC_RING_TO_DESC(shadow_base, write_index);
+
+		/* Update low 32 bits source descriptor address */
+		shadow_src_desc->buffer_addr =
+			(uint32_t)(dma_addr & 0xFFFFFFFF);
+#ifdef QCA_WIFI_3_0
+		shadow_src_desc->buffer_addr_hi =
+			(uint32_t)((dma_addr >> 32) & 0x1F);
+		user_flags |= shadow_src_desc->buffer_addr_hi;
+		memcpy(&(((uint32_t *)shadow_src_desc)[1]), &user_flags,
+			   sizeof(uint32_t));
+#endif
+		shadow_src_desc->meta_data = transfer_id;
+
+		/*
+		 * Set the swap bit if:
+		 * typical sends on this CE are swapped (host is big-endian)
+		 * and this send doesn't disable the swapping
+		 * (data is not bytestream)
+		 */
+		shadow_src_desc->byte_swap =
+			(((CE_state->attr_flags & CE_ATTR_BYTE_SWAP_DATA)
+			 != 0) & ((flags & CE_SEND_FLAG_SWAP_DISABLE) == 0));
+		shadow_src_desc->gather = ((flags & CE_SEND_FLAG_GATHER) != 0);
+		shadow_src_desc->nbytes = nbytes;
+
+		*src_desc = *shadow_src_desc;
+
+		src_ring->per_transfer_context[write_index] =
+			per_transfer_context;
+
+		/* Update Source Ring Write Index */
+		write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+
+		/* WORKAROUND */
+		if (!shadow_src_desc->gather) {
+			war_ce_src_ring_write_idx_set(scn, ctrl_addr,
+						      write_index);
+		}
+
+		src_ring->write_index = write_index;
+		status = CDF_STATUS_SUCCESS;
+	}
+	A_TARGET_ACCESS_END_RET(scn);
+
+	return status;
+}
+
+int
+ce_send(struct CE_handle *copyeng,
+		void *per_transfer_context,
+		cdf_dma_addr_t buffer,
+		uint32_t nbytes,
+		uint32_t transfer_id,
+		uint32_t flags,
+		uint32_t user_flag)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	int status;
+
+	cdf_spin_lock_bh(&CE_state->scn->target_lock);
+	status = ce_send_nolock(copyeng, per_transfer_context, buffer, nbytes,
+			transfer_id, flags, user_flag);
+	cdf_spin_unlock_bh(&CE_state->scn->target_lock);
+
+	return status;
+}
+
+unsigned int ce_sendlist_sizeof(void)
+{
+	return sizeof(struct ce_sendlist);
+}
+
+void ce_sendlist_init(struct ce_sendlist *sendlist)
+{
+	struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist;
+	sl->num_items = 0;
+}
+
+int
+ce_sendlist_buf_add(struct ce_sendlist *sendlist,
+					cdf_dma_addr_t buffer,
+					uint32_t nbytes,
+					uint32_t flags,
+					uint32_t user_flags)
+{
+	struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist;
+	unsigned int num_items = sl->num_items;
+	struct ce_sendlist_item *item;
+
+	if (num_items >= CE_SENDLIST_ITEMS_MAX) {
+		CDF_ASSERT(num_items < CE_SENDLIST_ITEMS_MAX);
+		return CDF_STATUS_E_RESOURCES;
+	}
+
+	item = &sl->item[num_items];
+	item->send_type = CE_SIMPLE_BUFFER_TYPE;
+	item->data = buffer;
+	item->u.nbytes = nbytes;
+	item->flags = flags;
+	item->user_flags = user_flags;
+	sl->num_items = num_items + 1;
+	return CDF_STATUS_SUCCESS;
+}
+
+int
+ce_sendlist_send(struct CE_handle *copyeng,
+		 void *per_transfer_context,
+		 struct ce_sendlist *sendlist, unsigned int transfer_id)
+{
+	int status = -ENOMEM;
+	struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist;
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	struct CE_ring_state *src_ring = CE_state->src_ring;
+	unsigned int nentries_mask = src_ring->nentries_mask;
+	unsigned int num_items = sl->num_items;
+	unsigned int sw_index;
+	unsigned int write_index;
+
+	CDF_ASSERT((num_items > 0) && (num_items < src_ring->nentries));
+
+	cdf_spin_lock_bh(&CE_state->scn->target_lock);
+	sw_index = src_ring->sw_index;
+	write_index = src_ring->write_index;
+
+	if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) >=
+	    num_items) {
+		struct ce_sendlist_item *item;
+		int i;
+
+		/* handle all but the last item uniformly */
+		for (i = 0; i < num_items - 1; i++) {
+			item = &sl->item[i];
+			/* TBDXXX: Support extensible sendlist_types? */
+			CDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE);
+			status = ce_send_nolock(copyeng, CE_SENDLIST_ITEM_CTXT,
+				(cdf_dma_addr_t) item->data,
+				item->u.nbytes, transfer_id,
+				item->flags | CE_SEND_FLAG_GATHER,
+				item->user_flags);
+			CDF_ASSERT(status == CDF_STATUS_SUCCESS);
+		}
+		/* provide valid context pointer for final item */
+		item = &sl->item[i];
+		/* TBDXXX: Support extensible sendlist_types? */
+		CDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE);
+		status = ce_send_nolock(copyeng, per_transfer_context,
+					(cdf_dma_addr_t) item->data,
+					item->u.nbytes,
+					transfer_id, item->flags,
+					item->user_flags);
+		CDF_ASSERT(status == CDF_STATUS_SUCCESS);
+		NBUF_UPDATE_TX_PKT_COUNT((cdf_nbuf_t)per_transfer_context,
+					NBUF_TX_PKT_CE);
+		DPTRACE(cdf_dp_trace((cdf_nbuf_t)per_transfer_context,
+			CDF_DP_TRACE_CE_PACKET_PTR_RECORD,
+			(uint8_t *)(((cdf_nbuf_t)per_transfer_context)->data),
+			sizeof(((cdf_nbuf_t)per_transfer_context)->data)));
+	} else {
+		/*
+		 * Probably not worth the additional complexity to support
+		 * partial sends with continuation or notification.  We expect
+		 * to use large rings and small sendlists. If we can't handle
+		 * the entire request at once, punt it back to the caller.
+		 */
+	}
+	cdf_spin_unlock_bh(&CE_state->scn->target_lock);
+
+	return status;
+}
+
+#ifdef WLAN_FEATURE_FASTPATH
+#ifdef QCA_WIFI_3_0
+static inline void
+ce_buffer_addr_hi_set(struct CE_src_desc *shadow_src_desc,
+		      uint64_t dma_addr,
+		      uint32_t user_flags)
+{
+	shadow_src_desc->buffer_addr_hi =
+			(uint32_t)((dma_addr >> 32) & 0x1F);
+	user_flags |= shadow_src_desc->buffer_addr_hi;
+	memcpy(&(((uint32_t *)shadow_src_desc)[1]), &user_flags,
+			sizeof(uint32_t));
+}
+#else
+static inline void
+ce_buffer_addr_hi_set(struct CE_src_desc *shadow_src_desc,
+		      uint64_t dma_addr,
+		      uint32_t user_flags)
+{
+}
+#endif
+
+/**
+ * ce_send_fast() CE layer Tx buffer posting function
+ * @copyeng: copy engine handle
+ * @msdus: iarray of msdu to be sent
+ * @num_msdus: number of msdus in an array
+ * @transfer_id: transfer_id
+ *
+ * Assumption : Called with an array of MSDU's
+ * Function:
+ * For each msdu in the array
+ * 1. Check no. of available entries
+ * 2. Create src ring entries (allocated in consistent memory
+ * 3. Write index to h/w
+ *
+ * Return: No. of packets that could be sent
+ */
+
+int ce_send_fast(struct CE_handle *copyeng, cdf_nbuf_t *msdus,
+		 unsigned int num_msdus, unsigned int transfer_id)
+{
+	struct CE_state *ce_state = (struct CE_state *)copyeng;
+	struct ol_softc *scn = ce_state->scn;
+	struct CE_ring_state *src_ring = ce_state->src_ring;
+	u_int32_t ctrl_addr = ce_state->ctrl_addr;
+	unsigned int nentries_mask = src_ring->nentries_mask;
+	unsigned int write_index;
+	unsigned int sw_index;
+	unsigned int frag_len;
+	cdf_nbuf_t msdu;
+	int i;
+	uint64_t dma_addr;
+	uint32_t user_flags = 0;
+
+	/*
+	 * This lock could be more fine-grained, one per CE,
+	 * TODO : Add this lock now.
+	 * That is the next step of optimization.
+	 */
+	cdf_spin_lock_bh(&scn->target_lock);
+	sw_index = src_ring->sw_index;
+	write_index = src_ring->write_index;
+
+	/* 2 msdus per packet */
+	for (i = 0; i < num_msdus; i++) {
+		struct CE_src_desc *src_ring_base =
+			(struct CE_src_desc *)src_ring->base_addr_owner_space;
+		struct CE_src_desc *shadow_base =
+			(struct CE_src_desc *)src_ring->shadow_base;
+		struct CE_src_desc *src_desc =
+			CE_SRC_RING_TO_DESC(src_ring_base, write_index);
+		struct CE_src_desc *shadow_src_desc =
+			CE_SRC_RING_TO_DESC(shadow_base, write_index);
+
+		msdu = msdus[i];
+
+		/*
+		 * First fill out the ring descriptor for the HTC HTT frame
+		 * header. These are uncached writes. Should we use a local
+		 * structure instead?
+		 */
+		/* HTT/HTC header can be passed as a argument */
+		dma_addr = cdf_nbuf_get_frag_paddr_lo(msdu, 0);
+		shadow_src_desc->buffer_addr = (uint32_t)(dma_addr &
+							  0xFFFFFFFF);
+		user_flags = cdf_nbuf_data_attr_get(msdu) & DESC_DATA_FLAG_MASK;
+		ce_buffer_addr_hi_set(shadow_src_desc, dma_addr, user_flags);
+
+		shadow_src_desc->meta_data = transfer_id;
+		shadow_src_desc->nbytes = cdf_nbuf_get_frag_len(msdu, 0);
+
+		/*
+		 * HTC HTT header is a word stream, so byte swap if CE byte
+		 * swap enabled
+		 */
+		shadow_src_desc->byte_swap = ((ce_state->attr_flags &
+					CE_ATTR_BYTE_SWAP_DATA) != 0);
+		/* For the first one, it still does not need to write */
+		shadow_src_desc->gather = 1;
+		*src_desc = *shadow_src_desc;
+
+		/* By default we could initialize the transfer context to this
+		 * value
+		 */
+		src_ring->per_transfer_context[write_index] =
+			CE_SENDLIST_ITEM_CTXT;
+
+		write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+
+		src_desc = CE_SRC_RING_TO_DESC(src_ring_base, write_index);
+		shadow_src_desc = CE_SRC_RING_TO_DESC(shadow_base, write_index);
+		/*
+		 * Now fill out the ring descriptor for the actual data
+		 * packet
+		 */
+		dma_addr = cdf_nbuf_get_frag_paddr_lo(msdu, 1);
+		shadow_src_desc->buffer_addr = (uint32_t)(dma_addr &
+							  0xFFFFFFFF);
+		/*
+		 * Clear packet offset for all but the first CE desc.
+		 */
+		user_flags &= ~CDF_CE_TX_PKT_OFFSET_BIT_M;
+		ce_buffer_addr_hi_set(shadow_src_desc, dma_addr, user_flags);
+		shadow_src_desc->meta_data = transfer_id;
+
+		/* get actual packet length */
+		frag_len = cdf_nbuf_get_frag_len(msdu, 1);
+		shadow_src_desc->nbytes = frag_len > ce_state->download_len ?
+			ce_state->download_len : frag_len;
+
+		/*  Data packet is a byte stream, so disable byte swap */
+		shadow_src_desc->byte_swap = 0;
+		/* For the last one, gather is not set */
+		shadow_src_desc->gather    = 0;
+		*src_desc = *shadow_src_desc;
+		src_ring->per_transfer_context[write_index] = msdu;
+		write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+	}
+
+	/* Write the final index to h/w one-shot */
+	if (i) {
+		src_ring->write_index = write_index;
+		/* Don't call WAR_XXX from here
+		 * Just call XXX instead, that has the reqd. intel
+		 */
+		war_ce_src_ring_write_idx_set(scn, ctrl_addr, write_index);
+	}
+
+	cdf_spin_unlock_bh(&scn->target_lock);
+
+	/*
+	 * If all packets in the array are transmitted,
+	 * i = num_msdus
+	 * Temporarily add an ASSERT
+	 */
+	ASSERT(i == num_msdus);
+	return i;
+}
+#endif /* WLAN_FEATURE_FASTPATH */
+
+int
+ce_recv_buf_enqueue(struct CE_handle *copyeng,
+		    void *per_recv_context, cdf_dma_addr_t buffer)
+{
+	int status;
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	struct CE_ring_state *dest_ring = CE_state->dest_ring;
+	uint32_t ctrl_addr = CE_state->ctrl_addr;
+	unsigned int nentries_mask = dest_ring->nentries_mask;
+	unsigned int write_index;
+	unsigned int sw_index;
+	int val = 0;
+	uint64_t dma_addr = buffer;
+	struct ol_softc *scn = CE_state->scn;
+
+	cdf_spin_lock_bh(&scn->target_lock);
+	write_index = dest_ring->write_index;
+	sw_index = dest_ring->sw_index;
+
+	A_TARGET_ACCESS_BEGIN_RET_EXT(scn, val);
+	if (val == -1) {
+		cdf_spin_unlock_bh(&scn->target_lock);
+		return val;
+	}
+
+	if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) {
+		struct CE_dest_desc *dest_ring_base =
+			(struct CE_dest_desc *)dest_ring->
+			    base_addr_owner_space;
+		struct CE_dest_desc *dest_desc =
+			CE_DEST_RING_TO_DESC(dest_ring_base, write_index);
+
+		/* Update low 32 bit destination descriptor */
+		dest_desc->buffer_addr = (uint32_t)(dma_addr & 0xFFFFFFFF);
+#ifdef QCA_WIFI_3_0
+		dest_desc->buffer_addr_hi =
+			(uint32_t)((dma_addr >> 32) & 0x1F);
+#endif
+		dest_desc->nbytes = 0;
+
+		dest_ring->per_transfer_context[write_index] =
+			per_recv_context;
+
+		/* Update Destination Ring Write Index */
+		write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+		CE_DEST_RING_WRITE_IDX_SET(scn, ctrl_addr, write_index);
+		dest_ring->write_index = write_index;
+		status = CDF_STATUS_SUCCESS;
+	} else {
+		status = CDF_STATUS_E_FAILURE;
+	}
+	A_TARGET_ACCESS_END_RET_EXT(scn, val);
+	if (val == -1) {
+		cdf_spin_unlock_bh(&scn->target_lock);
+		return val;
+	}
+
+	cdf_spin_unlock_bh(&scn->target_lock);
+
+	return status;
+}
+
+void
+ce_send_watermarks_set(struct CE_handle *copyeng,
+		       unsigned int low_alert_nentries,
+		       unsigned int high_alert_nentries)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	uint32_t ctrl_addr = CE_state->ctrl_addr;
+	struct ol_softc *scn = CE_state->scn;
+
+	cdf_spin_lock(&scn->target_lock);
+	CE_SRC_RING_LOWMARK_SET(scn, ctrl_addr, low_alert_nentries);
+	CE_SRC_RING_HIGHMARK_SET(scn, ctrl_addr, high_alert_nentries);
+	cdf_spin_unlock(&scn->target_lock);
+}
+
+void
+ce_recv_watermarks_set(struct CE_handle *copyeng,
+		       unsigned int low_alert_nentries,
+		       unsigned int high_alert_nentries)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	uint32_t ctrl_addr = CE_state->ctrl_addr;
+	struct ol_softc *scn = CE_state->scn;
+
+	cdf_spin_lock(&scn->target_lock);
+	CE_DEST_RING_LOWMARK_SET(scn, ctrl_addr,
+				low_alert_nentries);
+	CE_DEST_RING_HIGHMARK_SET(scn, ctrl_addr,
+				high_alert_nentries);
+	cdf_spin_unlock(&scn->target_lock);
+}
+
+unsigned int ce_send_entries_avail(struct CE_handle *copyeng)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	struct CE_ring_state *src_ring = CE_state->src_ring;
+	unsigned int nentries_mask = src_ring->nentries_mask;
+	unsigned int sw_index;
+	unsigned int write_index;
+
+	cdf_spin_lock(&CE_state->scn->target_lock);
+	sw_index = src_ring->sw_index;
+	write_index = src_ring->write_index;
+	cdf_spin_unlock(&CE_state->scn->target_lock);
+
+	return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
+}
+
+unsigned int ce_recv_entries_avail(struct CE_handle *copyeng)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	struct CE_ring_state *dest_ring = CE_state->dest_ring;
+	unsigned int nentries_mask = dest_ring->nentries_mask;
+	unsigned int sw_index;
+	unsigned int write_index;
+
+	cdf_spin_lock(&CE_state->scn->target_lock);
+	sw_index = dest_ring->sw_index;
+	write_index = dest_ring->write_index;
+	cdf_spin_unlock(&CE_state->scn->target_lock);
+
+	return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
+}
+
+/*
+ * Guts of ce_send_entries_done.
+ * The caller takes responsibility for any necessary locking.
+ */
+unsigned int
+ce_send_entries_done_nolock(struct ol_softc *scn,
+			    struct CE_state *CE_state)
+{
+	struct CE_ring_state *src_ring = CE_state->src_ring;
+	uint32_t ctrl_addr = CE_state->ctrl_addr;
+	unsigned int nentries_mask = src_ring->nentries_mask;
+	unsigned int sw_index;
+	unsigned int read_index;
+
+	sw_index = src_ring->sw_index;
+	read_index = CE_SRC_RING_READ_IDX_GET(scn, ctrl_addr);
+
+	return CE_RING_DELTA(nentries_mask, sw_index, read_index);
+}
+
+unsigned int ce_send_entries_done(struct CE_handle *copyeng)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	unsigned int nentries;
+
+	cdf_spin_lock(&CE_state->scn->target_lock);
+	nentries = ce_send_entries_done_nolock(CE_state->scn, CE_state);
+	cdf_spin_unlock(&CE_state->scn->target_lock);
+
+	return nentries;
+}
+
+/*
+ * Guts of ce_recv_entries_done.
+ * The caller takes responsibility for any necessary locking.
+ */
+unsigned int
+ce_recv_entries_done_nolock(struct ol_softc *scn,
+			    struct CE_state *CE_state)
+{
+	struct CE_ring_state *dest_ring = CE_state->dest_ring;
+	uint32_t ctrl_addr = CE_state->ctrl_addr;
+	unsigned int nentries_mask = dest_ring->nentries_mask;
+	unsigned int sw_index;
+	unsigned int read_index;
+
+	sw_index = dest_ring->sw_index;
+	read_index = CE_DEST_RING_READ_IDX_GET(scn, ctrl_addr);
+
+	return CE_RING_DELTA(nentries_mask, sw_index, read_index);
+}
+
+unsigned int ce_recv_entries_done(struct CE_handle *copyeng)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	unsigned int nentries;
+
+	cdf_spin_lock(&CE_state->scn->target_lock);
+	nentries = ce_recv_entries_done_nolock(CE_state->scn, CE_state);
+	cdf_spin_unlock(&CE_state->scn->target_lock);
+
+	return nentries;
+}
+
+/* Debug support */
+void *ce_debug_cmplrn_context;  /* completed recv next context */
+void *ce_debug_cnclsn_context;  /* cancel send next context */
+void *ce_debug_rvkrn_context;   /* revoke receive next context */
+void *ce_debug_cmplsn_context;  /* completed send next context */
+
+/*
+ * Guts of ce_completed_recv_next.
+ * The caller takes responsibility for any necessary locking.
+ */
+int
+ce_completed_recv_next_nolock(struct CE_state *CE_state,
+			      void **per_CE_contextp,
+			      void **per_transfer_contextp,
+			      cdf_dma_addr_t *bufferp,
+			      unsigned int *nbytesp,
+			      unsigned int *transfer_idp,
+			      unsigned int *flagsp)
+{
+	int status;
+	struct CE_ring_state *dest_ring = CE_state->dest_ring;
+	unsigned int nentries_mask = dest_ring->nentries_mask;
+	unsigned int sw_index = dest_ring->sw_index;
+
+	struct CE_dest_desc *dest_ring_base =
+		(struct CE_dest_desc *)dest_ring->base_addr_owner_space;
+	struct CE_dest_desc *dest_desc =
+		CE_DEST_RING_TO_DESC(dest_ring_base, sw_index);
+	int nbytes;
+	struct CE_dest_desc dest_desc_info;
+	/*
+	 * By copying the dest_desc_info element to local memory, we could
+	 * avoid extra memory read from non-cachable memory.
+	 */
+	dest_desc_info =  *dest_desc;
+	nbytes = dest_desc_info.nbytes;
+	if (nbytes == 0) {
+		/*
+		 * This closes a relatively unusual race where the Host
+		 * sees the updated DRRI before the update to the
+		 * corresponding descriptor has completed. We treat this
+		 * as a descriptor that is not yet done.
+		 */
+		status = CDF_STATUS_E_FAILURE;
+		goto done;
+	}
+
+	dest_desc->nbytes = 0;
+
+	/* Return data from completed destination descriptor */
+	*bufferp = HIF_CE_DESC_ADDR_TO_DMA(&dest_desc_info);
+	*nbytesp = nbytes;
+	*transfer_idp = dest_desc_info.meta_data;
+	*flagsp = (dest_desc_info.byte_swap) ? CE_RECV_FLAG_SWAPPED : 0;
+
+	if (per_CE_contextp) {
+		*per_CE_contextp = CE_state->recv_context;
+	}
+
+	ce_debug_cmplrn_context = dest_ring->per_transfer_context[sw_index];
+	if (per_transfer_contextp) {
+		*per_transfer_contextp = ce_debug_cmplrn_context;
+	}
+	dest_ring->per_transfer_context[sw_index] = 0;  /* sanity */
+
+	/* Update sw_index */
+	sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
+	dest_ring->sw_index = sw_index;
+	status = CDF_STATUS_SUCCESS;
+
+done:
+	return status;
+}
+
+int
+ce_completed_recv_next(struct CE_handle *copyeng,
+		       void **per_CE_contextp,
+		       void **per_transfer_contextp,
+		       cdf_dma_addr_t *bufferp,
+		       unsigned int *nbytesp,
+		       unsigned int *transfer_idp, unsigned int *flagsp)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	int status;
+
+	cdf_spin_lock_bh(&CE_state->scn->target_lock);
+	status =
+		ce_completed_recv_next_nolock(CE_state, per_CE_contextp,
+					      per_transfer_contextp, bufferp,
+					      nbytesp, transfer_idp, flagsp);
+	cdf_spin_unlock_bh(&CE_state->scn->target_lock);
+
+	return status;
+}
+
+/* NB: Modeled after ce_completed_recv_next_nolock */
+CDF_STATUS
+ce_revoke_recv_next(struct CE_handle *copyeng,
+		    void **per_CE_contextp,
+		    void **per_transfer_contextp, cdf_dma_addr_t *bufferp)
+{
+	struct CE_state *CE_state;
+	struct CE_ring_state *dest_ring;
+	unsigned int nentries_mask;
+	unsigned int sw_index;
+	unsigned int write_index;
+	CDF_STATUS status;
+	struct ol_softc *scn;
+
+	CE_state = (struct CE_state *)copyeng;
+	dest_ring = CE_state->dest_ring;
+	if (!dest_ring) {
+		return CDF_STATUS_E_FAILURE;
+	}
+
+	scn = CE_state->scn;
+	cdf_spin_lock(&scn->target_lock);
+	nentries_mask = dest_ring->nentries_mask;
+	sw_index = dest_ring->sw_index;
+	write_index = dest_ring->write_index;
+	if (write_index != sw_index) {
+		struct CE_dest_desc *dest_ring_base =
+			(struct CE_dest_desc *)dest_ring->
+			    base_addr_owner_space;
+		struct CE_dest_desc *dest_desc =
+			CE_DEST_RING_TO_DESC(dest_ring_base, sw_index);
+
+		/* Return data from completed destination descriptor */
+		*bufferp = HIF_CE_DESC_ADDR_TO_DMA(dest_desc);
+
+		if (per_CE_contextp) {
+			*per_CE_contextp = CE_state->recv_context;
+		}
+
+		ce_debug_rvkrn_context =
+			dest_ring->per_transfer_context[sw_index];
+		if (per_transfer_contextp) {
+			*per_transfer_contextp = ce_debug_rvkrn_context;
+		}
+		dest_ring->per_transfer_context[sw_index] = 0;  /* sanity */
+
+		/* Update sw_index */
+		sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
+		dest_ring->sw_index = sw_index;
+		status = CDF_STATUS_SUCCESS;
+	} else {
+		status = CDF_STATUS_E_FAILURE;
+	}
+	cdf_spin_unlock(&scn->target_lock);
+
+	return status;
+}
+
+/*
+ * Guts of ce_completed_send_next.
+ * The caller takes responsibility for any necessary locking.
+ */
+int
+ce_completed_send_next_nolock(struct CE_state *CE_state,
+			      void **per_CE_contextp,
+			      void **per_transfer_contextp,
+			      cdf_dma_addr_t *bufferp,
+			      unsigned int *nbytesp,
+			      unsigned int *transfer_idp,
+			      unsigned int *sw_idx,
+			      unsigned int *hw_idx,
+			      uint32_t *toeplitz_hash_result)
+{
+	int status = CDF_STATUS_E_FAILURE;
+	struct CE_ring_state *src_ring = CE_state->src_ring;
+	uint32_t ctrl_addr = CE_state->ctrl_addr;
+	unsigned int nentries_mask = src_ring->nentries_mask;
+	unsigned int sw_index = src_ring->sw_index;
+	unsigned int read_index;
+	struct ol_softc *scn = CE_state->scn;
+
+	if (src_ring->hw_index == sw_index) {
+		/*
+		 * The SW completion index has caught up with the cached
+		 * version of the HW completion index.
+		 * Update the cached HW completion index to see whether
+		 * the SW has really caught up to the HW, or if the cached
+		 * value of the HW index has become stale.
+		 */
+		A_TARGET_ACCESS_BEGIN_RET(scn);
+		src_ring->hw_index =
+			CE_SRC_RING_READ_IDX_GET(scn, ctrl_addr);
+		A_TARGET_ACCESS_END_RET(scn);
+	}
+	read_index = src_ring->hw_index;
+
+	if (sw_idx)
+		*sw_idx = sw_index;
+
+	if (hw_idx)
+		*hw_idx = read_index;
+
+	if ((read_index != sw_index) && (read_index != 0xffffffff)) {
+		struct CE_src_desc *shadow_base =
+			(struct CE_src_desc *)src_ring->shadow_base;
+		struct CE_src_desc *shadow_src_desc =
+			CE_SRC_RING_TO_DESC(shadow_base, sw_index);
+#ifdef QCA_WIFI_3_0
+		struct CE_src_desc *src_ring_base =
+			(struct CE_src_desc *)src_ring->base_addr_owner_space;
+		struct CE_src_desc *src_desc =
+			CE_SRC_RING_TO_DESC(src_ring_base, sw_index);
+#endif
+		/* Return data from completed source descriptor */
+		*bufferp = HIF_CE_DESC_ADDR_TO_DMA(shadow_src_desc);
+		*nbytesp = shadow_src_desc->nbytes;
+		*transfer_idp = shadow_src_desc->meta_data;
+#ifdef QCA_WIFI_3_0
+		*toeplitz_hash_result = src_desc->toeplitz_hash_result;
+#else
+		*toeplitz_hash_result = 0;
+#endif
+		if (per_CE_contextp) {
+			*per_CE_contextp = CE_state->send_context;
+		}
+
+		ce_debug_cmplsn_context =
+			src_ring->per_transfer_context[sw_index];
+		if (per_transfer_contextp) {
+			*per_transfer_contextp = ce_debug_cmplsn_context;
+		}
+		src_ring->per_transfer_context[sw_index] = 0;   /* sanity */
+
+		/* Update sw_index */
+		sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
+		src_ring->sw_index = sw_index;
+		status = CDF_STATUS_SUCCESS;
+	}
+
+	return status;
+}
+
+/* NB: Modeled after ce_completed_send_next */
+CDF_STATUS
+ce_cancel_send_next(struct CE_handle *copyeng,
+		void **per_CE_contextp,
+		void **per_transfer_contextp,
+		cdf_dma_addr_t *bufferp,
+		unsigned int *nbytesp,
+		unsigned int *transfer_idp,
+		uint32_t *toeplitz_hash_result)
+{
+	struct CE_state *CE_state;
+	struct CE_ring_state *src_ring;
+	unsigned int nentries_mask;
+	unsigned int sw_index;
+	unsigned int write_index;
+	CDF_STATUS status;
+	struct ol_softc *scn;
+
+	CE_state = (struct CE_state *)copyeng;
+	src_ring = CE_state->src_ring;
+	if (!src_ring) {
+		return CDF_STATUS_E_FAILURE;
+	}
+
+	scn = CE_state->scn;
+	cdf_spin_lock(&CE_state->scn->target_lock);
+	nentries_mask = src_ring->nentries_mask;
+	sw_index = src_ring->sw_index;
+	write_index = src_ring->write_index;
+
+	if (write_index != sw_index) {
+		struct CE_src_desc *src_ring_base =
+			(struct CE_src_desc *)src_ring->base_addr_owner_space;
+		struct CE_src_desc *src_desc =
+			CE_SRC_RING_TO_DESC(src_ring_base, sw_index);
+
+		/* Return data from completed source descriptor */
+		*bufferp = HIF_CE_DESC_ADDR_TO_DMA(src_desc);
+		*nbytesp = src_desc->nbytes;
+		*transfer_idp = src_desc->meta_data;
+#ifdef QCA_WIFI_3_0
+		*toeplitz_hash_result = src_desc->toeplitz_hash_result;
+#else
+		*toeplitz_hash_result = 0;
+#endif
+
+		if (per_CE_contextp) {
+			*per_CE_contextp = CE_state->send_context;
+		}
+
+		ce_debug_cnclsn_context =
+			src_ring->per_transfer_context[sw_index];
+		if (per_transfer_contextp) {
+			*per_transfer_contextp = ce_debug_cnclsn_context;
+		}
+		src_ring->per_transfer_context[sw_index] = 0;   /* sanity */
+
+		/* Update sw_index */
+		sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
+		src_ring->sw_index = sw_index;
+		status = CDF_STATUS_SUCCESS;
+	} else {
+		status = CDF_STATUS_E_FAILURE;
+	}
+	cdf_spin_unlock(&CE_state->scn->target_lock);
+
+	return status;
+}
+
+/* Shift bits to convert IS_*_RING_*_WATERMARK_MASK to CE_WM_FLAG_*_* */
+#define CE_WM_SHFT 1
+
+int
+ce_completed_send_next(struct CE_handle *copyeng,
+		       void **per_CE_contextp,
+		       void **per_transfer_contextp,
+		       cdf_dma_addr_t *bufferp,
+		       unsigned int *nbytesp,
+		       unsigned int *transfer_idp,
+		       unsigned int *sw_idx,
+		       unsigned int *hw_idx,
+		       unsigned int *toeplitz_hash_result)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	int status;
+
+	cdf_spin_lock_bh(&CE_state->scn->target_lock);
+	status =
+		ce_completed_send_next_nolock(CE_state, per_CE_contextp,
+					      per_transfer_contextp, bufferp,
+					      nbytesp, transfer_idp, sw_idx,
+					      hw_idx, toeplitz_hash_result);
+	cdf_spin_unlock_bh(&CE_state->scn->target_lock);
+
+	return status;
+}
+
+#ifdef ATH_11AC_TXCOMPACT
+/* CE engine descriptor reap
+ * Similar to ce_per_engine_service , Only difference is ce_per_engine_service
+ * does recieve and reaping of completed descriptor ,
+ * This function only handles reaping of Tx complete descriptor.
+ * The Function is called from threshold reap  poll routine
+ * hif_send_complete_check so should not countain recieve functionality
+ * within it .
+ */
+
+void ce_per_engine_servicereap(struct ol_softc *scn, unsigned int CE_id)
+{
+	void *CE_context;
+	void *transfer_context;
+	cdf_dma_addr_t buf;
+	unsigned int nbytes;
+	unsigned int id;
+	unsigned int sw_idx, hw_idx;
+	uint32_t toeplitz_hash_result;
+	struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
+
+	A_TARGET_ACCESS_BEGIN(scn);
+
+	/* Since this function is called from both user context and
+	 * tasklet context the spinlock has to lock the bottom halves.
+	 * This fix assumes that ATH_11AC_TXCOMPACT flag is always
+	 * enabled in TX polling mode. If this is not the case, more
+	 * bottom halve spin lock changes are needed. Due to data path
+	 * performance concern, after internal discussion we've decided
+	 * to make minimum change, i.e., only address the issue occured
+	 * in this function. The possible negative effect of this minimum
+	 * change is that, in the future, if some other function will also
+	 * be opened to let the user context to use, those cases need to be
+	 * addressed by change spin_lock to spin_lock_bh also.
+	 */
+
+	cdf_spin_lock_bh(&scn->target_lock);
+
+	if (CE_state->send_cb) {
+		{
+			/* Pop completed send buffers and call the
+			 * registered send callback for each
+			 */
+			while (ce_completed_send_next_nolock
+				 (CE_state, &CE_context,
+				  &transfer_context, &buf,
+				  &nbytes, &id, &sw_idx, &hw_idx,
+				  &toeplitz_hash_result) ==
+				  CDF_STATUS_SUCCESS) {
+				if (CE_id != CE_HTT_H2T_MSG) {
+					cdf_spin_unlock_bh(&scn->target_lock);
+					CE_state->
+					send_cb((struct CE_handle *)
+						CE_state, CE_context,
+						transfer_context, buf,
+						nbytes, id, sw_idx, hw_idx,
+						toeplitz_hash_result);
+					cdf_spin_lock_bh(&scn->target_lock);
+				} else {
+					struct HIF_CE_pipe_info *pipe_info =
+						(struct HIF_CE_pipe_info *)
+						CE_context;
+
+					cdf_spin_lock_bh(&pipe_info->
+						 completion_freeq_lock);
+					pipe_info->num_sends_allowed++;
+					cdf_spin_unlock_bh(&pipe_info->
+						   completion_freeq_lock);
+				}
+			}
+		}
+	}
+
+	cdf_spin_unlock_bh(&scn->target_lock);
+	A_TARGET_ACCESS_END(scn);
+}
+
+#endif /*ATH_11AC_TXCOMPACT */
+
+/*
+ * Number of times to check for any pending tx/rx completion on
+ * a copy engine, this count should be big enough. Once we hit
+ * this threashold we'll not check for any Tx/Rx comlpetion in same
+ * interrupt handling. Note that this threashold is only used for
+ * Rx interrupt processing, this can be used tor Tx as well if we
+ * suspect any infinite loop in checking for pending Tx completion.
+ */
+#define CE_TXRX_COMP_CHECK_THRESHOLD 20
+
+/*
+ * Guts of interrupt handler for per-engine interrupts on a particular CE.
+ *
+ * Invokes registered callbacks for recv_complete,
+ * send_complete, and watermarks.
+ *
+ * Returns: number of messages processed
+ */
+
+int ce_per_engine_service(struct ol_softc *scn, unsigned int CE_id)
+{
+	struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
+	uint32_t ctrl_addr = CE_state->ctrl_addr;
+	void *CE_context;
+	void *transfer_context;
+	cdf_dma_addr_t buf;
+	unsigned int nbytes;
+	unsigned int id;
+	unsigned int flags;
+	uint32_t CE_int_status;
+	unsigned int more_comp_cnt = 0;
+	unsigned int more_snd_comp_cnt = 0;
+	unsigned int sw_idx, hw_idx;
+	uint32_t toeplitz_hash_result;
+
+	if (Q_TARGET_ACCESS_BEGIN(scn) < 0) {
+		HIF_ERROR("[premature rc=0]\n");
+		return 0; /* no work done */
+	}
+
+	cdf_spin_lock(&scn->target_lock);
+
+	/* Clear force_break flag and re-initialize receive_count to 0 */
+
+	/* NAPI: scn variables- thread/multi-processing safety? */
+	scn->receive_count = 0;
+	scn->force_break = 0;
+more_completions:
+	if (CE_state->recv_cb) {
+
+		/* Pop completed recv buffers and call
+		 * the registered recv callback for each
+		 */
+		while (ce_completed_recv_next_nolock
+				(CE_state, &CE_context, &transfer_context,
+				&buf, &nbytes, &id, &flags) ==
+				CDF_STATUS_SUCCESS) {
+			cdf_spin_unlock(&scn->target_lock);
+			CE_state->recv_cb((struct CE_handle *)CE_state,
+					  CE_context, transfer_context, buf,
+					  nbytes, id, flags);
+
+			/*
+			 * EV #112693 -
+			 * [Peregrine][ES1][WB342][Win8x86][Performance]
+			 * BSoD_0x133 occurred in VHT80 UDP_DL
+			 * Break out DPC by force if number of loops in
+			 * hif_pci_ce_recv_data reaches MAX_NUM_OF_RECEIVES
+			 * to avoid spending too long time in
+			 * DPC for each interrupt handling. Schedule another
+			 * DPC to avoid data loss if we had taken
+			 * force-break action before apply to Windows OS
+			 * only currently, Linux/MAC os can expand to their
+			 * platform if necessary
+			 */
+
+			/* Break the receive processes by
+			 * force if force_break set up
+			 */
+			if (cdf_unlikely(scn->force_break)) {
+				cdf_atomic_set(&CE_state->rx_pending, 1);
+				CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr,
+					HOST_IS_COPY_COMPLETE_MASK);
+				if (Q_TARGET_ACCESS_END(scn) < 0)
+					HIF_ERROR("<--[premature rc=%d]\n",
+						  scn->receive_count);
+				return scn->receive_count;
+			}
+			cdf_spin_lock(&scn->target_lock);
+		}
+	}
+
+	/*
+	 * Attention: We may experience potential infinite loop for below
+	 * While Loop during Sending Stress test.
+	 * Resolve the same way as Receive Case (Refer to EV #112693)
+	 */
+
+	if (CE_state->send_cb) {
+		/* Pop completed send buffers and call
+		 * the registered send callback for each
+		 */
+
+#ifdef ATH_11AC_TXCOMPACT
+		while (ce_completed_send_next_nolock
+			 (CE_state, &CE_context,
+			 &transfer_context, &buf, &nbytes,
+			 &id, &sw_idx, &hw_idx,
+			 &toeplitz_hash_result) == CDF_STATUS_SUCCESS) {
+
+			if (CE_id != CE_HTT_H2T_MSG ||
+			    WLAN_IS_EPPING_ENABLED(cds_get_conparam())) {
+				cdf_spin_unlock(&scn->target_lock);
+				CE_state->send_cb((struct CE_handle *)CE_state,
+						  CE_context, transfer_context,
+						  buf, nbytes, id, sw_idx,
+						  hw_idx, toeplitz_hash_result);
+				cdf_spin_lock(&scn->target_lock);
+			} else {
+				struct HIF_CE_pipe_info *pipe_info =
+					(struct HIF_CE_pipe_info *)CE_context;
+
+				cdf_spin_lock(&pipe_info->
+					      completion_freeq_lock);
+				pipe_info->num_sends_allowed++;
+				cdf_spin_unlock(&pipe_info->
+						completion_freeq_lock);
+			}
+		}
+#else                           /*ATH_11AC_TXCOMPACT */
+		while (ce_completed_send_next_nolock
+			 (CE_state, &CE_context,
+			  &transfer_context, &buf, &nbytes,
+			  &id, &sw_idx, &hw_idx,
+			  &toeplitz_hash_result) == CDF_STATUS_SUCCESS) {
+			cdf_spin_unlock(&scn->target_lock);
+			CE_state->send_cb((struct CE_handle *)CE_state,
+				  CE_context, transfer_context, buf,
+				  nbytes, id, sw_idx, hw_idx,
+				  toeplitz_hash_result);
+			cdf_spin_lock(&scn->target_lock);
+		}
+#endif /*ATH_11AC_TXCOMPACT */
+	}
+
+more_watermarks:
+	if (CE_state->misc_cbs) {
+		CE_int_status = CE_ENGINE_INT_STATUS_GET(scn, ctrl_addr);
+		if (CE_int_status & CE_WATERMARK_MASK) {
+			if (CE_state->watermark_cb) {
+
+				cdf_spin_unlock(&scn->target_lock);
+				/* Convert HW IS bits to software flags */
+				flags =
+					(CE_int_status & CE_WATERMARK_MASK) >>
+					CE_WM_SHFT;
+
+				CE_state->
+				watermark_cb((struct CE_handle *)CE_state,
+					     CE_state->wm_context, flags);
+				cdf_spin_lock(&scn->target_lock);
+			}
+		}
+	}
+
+	/*
+	 * Clear the misc interrupts (watermark) that were handled above,
+	 * and that will be checked again below.
+	 * Clear and check for copy-complete interrupts again, just in case
+	 * more copy completions happened while the misc interrupts were being
+	 * handled.
+	 */
+	CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr,
+				   CE_WATERMARK_MASK |
+				   HOST_IS_COPY_COMPLETE_MASK);
+
+	/*
+	 * Now that per-engine interrupts are cleared, verify that
+	 * no recv interrupts arrive while processing send interrupts,
+	 * and no recv or send interrupts happened while processing
+	 * misc interrupts.Go back and check again.Keep checking until
+	 * we find no more events to process.
+	 */
+	if (CE_state->recv_cb && ce_recv_entries_done_nolock(scn, CE_state)) {
+		if (WLAN_IS_EPPING_ENABLED(cds_get_conparam()) ||
+		    more_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) {
+			goto more_completions;
+		} else {
+			HIF_ERROR(
+				"%s:Potential infinite loop detected during Rx processing nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x",
+				__func__, CE_state->dest_ring->nentries_mask,
+				CE_state->dest_ring->sw_index,
+				CE_DEST_RING_READ_IDX_GET(scn,
+							  CE_state->ctrl_addr));
+		}
+	}
+
+	if (CE_state->send_cb && ce_send_entries_done_nolock(scn, CE_state)) {
+		if (WLAN_IS_EPPING_ENABLED(cds_get_conparam()) ||
+		    more_snd_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) {
+			goto more_completions;
+		} else {
+			HIF_ERROR(
+				"%s:Potential infinite loop detected during send completion nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x",
+				__func__, CE_state->src_ring->nentries_mask,
+				CE_state->src_ring->sw_index,
+				CE_SRC_RING_READ_IDX_GET(scn,
+							 CE_state->ctrl_addr));
+		}
+	}
+
+	if (CE_state->misc_cbs) {
+		CE_int_status = CE_ENGINE_INT_STATUS_GET(scn, ctrl_addr);
+		if (CE_int_status & CE_WATERMARK_MASK) {
+			if (CE_state->watermark_cb) {
+				goto more_watermarks;
+			}
+		}
+	}
+
+	cdf_spin_unlock(&scn->target_lock);
+	cdf_atomic_set(&CE_state->rx_pending, 0);
+
+	if (Q_TARGET_ACCESS_END(scn) < 0)
+		HIF_ERROR("<--[premature rc=%d]\n", scn->receive_count);
+	return scn->receive_count;
+}
+
+/*
+ * Handler for per-engine interrupts on ALL active CEs.
+ * This is used in cases where the system is sharing a
+ * single interrput for all CEs
+ */
+
+void ce_per_engine_service_any(int irq, struct ol_softc *scn)
+{
+	int CE_id;
+	uint32_t intr_summary;
+
+	A_TARGET_ACCESS_BEGIN(scn);
+	if (!cdf_atomic_read(&scn->tasklet_from_intr)) {
+		for (CE_id = 0; CE_id < scn->ce_count; CE_id++) {
+			struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
+			if (cdf_atomic_read(&CE_state->rx_pending)) {
+				cdf_atomic_set(&CE_state->rx_pending, 0);
+				ce_per_engine_service(scn, CE_id);
+			}
+		}
+
+		A_TARGET_ACCESS_END(scn);
+		return;
+	}
+
+	intr_summary = CE_INTERRUPT_SUMMARY(scn);
+
+	for (CE_id = 0; intr_summary && (CE_id < scn->ce_count); CE_id++) {
+		if (intr_summary & (1 << CE_id)) {
+			intr_summary &= ~(1 << CE_id);
+		} else {
+			continue;       /* no intr pending on this CE */
+		}
+
+		ce_per_engine_service(scn, CE_id);
+	}
+
+	A_TARGET_ACCESS_END(scn);
+}
+
+/*
+ * Adjust interrupts for the copy complete handler.
+ * If it's needed for either send or recv, then unmask
+ * this interrupt; otherwise, mask it.
+ *
+ * Called with target_lock held.
+ */
+static void
+ce_per_engine_handler_adjust(struct CE_state *CE_state,
+			     int disable_copy_compl_intr)
+{
+	uint32_t ctrl_addr = CE_state->ctrl_addr;
+	struct ol_softc *scn = CE_state->scn;
+
+	CE_state->disable_copy_compl_intr = disable_copy_compl_intr;
+	A_TARGET_ACCESS_BEGIN(scn);
+	if ((!disable_copy_compl_intr) &&
+	    (CE_state->send_cb || CE_state->recv_cb)) {
+		CE_COPY_COMPLETE_INTR_ENABLE(scn, ctrl_addr);
+	} else {
+		CE_COPY_COMPLETE_INTR_DISABLE(scn, ctrl_addr);
+	}
+
+	if (CE_state->watermark_cb) {
+		CE_WATERMARK_INTR_ENABLE(scn, ctrl_addr);
+	} else {
+		CE_WATERMARK_INTR_DISABLE(scn, ctrl_addr);
+	}
+	A_TARGET_ACCESS_END(scn);
+
+}
+
+/*Iterate the CE_state list and disable the compl interrupt
+ * if it has been registered already.
+ */
+void ce_disable_any_copy_compl_intr_nolock(struct ol_softc *scn)
+{
+	int CE_id;
+
+	A_TARGET_ACCESS_BEGIN(scn);
+	for (CE_id = 0; CE_id < scn->ce_count; CE_id++) {
+		struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
+		uint32_t ctrl_addr = CE_state->ctrl_addr;
+
+		/* if the interrupt is currently enabled, disable it */
+		if (!CE_state->disable_copy_compl_intr
+		    && (CE_state->send_cb || CE_state->recv_cb)) {
+			CE_COPY_COMPLETE_INTR_DISABLE(scn, ctrl_addr);
+		}
+
+		if (CE_state->watermark_cb) {
+			CE_WATERMARK_INTR_DISABLE(scn, ctrl_addr);
+		}
+	}
+	A_TARGET_ACCESS_END(scn);
+}
+
+void ce_enable_any_copy_compl_intr_nolock(struct ol_softc *scn)
+{
+	int CE_id;
+
+	A_TARGET_ACCESS_BEGIN(scn);
+	for (CE_id = 0; CE_id < scn->ce_count; CE_id++) {
+		struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
+		uint32_t ctrl_addr = CE_state->ctrl_addr;
+
+		/*
+		 * If the CE is supposed to have copy complete interrupts
+		 * enabled (i.e. there a callback registered, and the
+		 * "disable" flag is not set), then re-enable the interrupt.
+		 */
+		if (!CE_state->disable_copy_compl_intr
+		    && (CE_state->send_cb || CE_state->recv_cb)) {
+			CE_COPY_COMPLETE_INTR_ENABLE(scn, ctrl_addr);
+		}
+
+		if (CE_state->watermark_cb) {
+			CE_WATERMARK_INTR_ENABLE(scn, ctrl_addr);
+		}
+	}
+	A_TARGET_ACCESS_END(scn);
+}
+
+void ce_disable_any_copy_compl_intr(struct ol_softc *scn)
+{
+	cdf_spin_lock(&scn->target_lock);
+	ce_disable_any_copy_compl_intr_nolock(scn);
+	cdf_spin_unlock(&scn->target_lock);
+}
+
+/*Re-enable the copy compl interrupt if it has not been disabled before.*/
+void ce_enable_any_copy_compl_intr(struct ol_softc *scn)
+{
+	cdf_spin_lock(&scn->target_lock);
+	ce_enable_any_copy_compl_intr_nolock(scn);
+	cdf_spin_unlock(&scn->target_lock);
+}
+
+void
+ce_send_cb_register(struct CE_handle *copyeng,
+		    ce_send_cb fn_ptr,
+		    void *ce_send_context, int disable_interrupts)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+
+	cdf_spin_lock(&CE_state->scn->target_lock);
+	CE_state->send_cb = fn_ptr;
+	CE_state->send_context = ce_send_context;
+	ce_per_engine_handler_adjust(CE_state, disable_interrupts);
+	cdf_spin_unlock(&CE_state->scn->target_lock);
+}
+
+void
+ce_recv_cb_register(struct CE_handle *copyeng,
+		    CE_recv_cb fn_ptr,
+		    void *CE_recv_context, int disable_interrupts)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+
+	cdf_spin_lock(&CE_state->scn->target_lock);
+	CE_state->recv_cb = fn_ptr;
+	CE_state->recv_context = CE_recv_context;
+	ce_per_engine_handler_adjust(CE_state, disable_interrupts);
+	cdf_spin_unlock(&CE_state->scn->target_lock);
+}
+
+void
+ce_watermark_cb_register(struct CE_handle *copyeng,
+			 CE_watermark_cb fn_ptr, void *CE_wm_context)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+
+	cdf_spin_lock(&CE_state->scn->target_lock);
+	CE_state->watermark_cb = fn_ptr;
+	CE_state->wm_context = CE_wm_context;
+	ce_per_engine_handler_adjust(CE_state, 0);
+	if (fn_ptr) {
+		CE_state->misc_cbs = 1;
+	}
+	cdf_spin_unlock(&CE_state->scn->target_lock);
+}
+
+#ifdef WLAN_FEATURE_FASTPATH
+/**
+ * ce_pkt_dl_len_set() set the HTT packet download length
+ * @hif_sc: HIF context
+ * @pkt_download_len: download length
+ *
+ * Return: None
+ */
+void ce_pkt_dl_len_set(void *hif_sc, u_int32_t pkt_download_len)
+{
+	struct ol_softc *sc = (struct ol_softc *)(hif_sc);
+	struct CE_state *ce_state = sc->ce_id_to_state[CE_HTT_H2T_MSG];
+
+	cdf_assert_always(ce_state);
+
+	cdf_spin_lock_bh(&sc->target_lock);
+	ce_state->download_len = pkt_download_len;
+	cdf_spin_unlock_bh(&sc->target_lock);
+
+	cdf_print("%s CE %d Pkt download length %d\n", __func__,
+		  ce_state->id, ce_state->download_len);
+}
+#else
+void ce_pkt_dl_len_set(void *hif_sc, u_int32_t pkt_download_len)
+{
+}
+#endif /* WLAN_FEATURE_FASTPATH */
+
+bool ce_get_rx_pending(struct ol_softc *scn)
+{
+	int CE_id;
+
+	for (CE_id = 0; CE_id < scn->ce_count; CE_id++) {
+		struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
+		if (cdf_atomic_read(&CE_state->rx_pending))
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ * ce_check_rx_pending() - ce_check_rx_pending
+ * @scn: ol_softc
+ * @ce_id: ce_id
+ *
+ * Return: bool
+ */
+bool ce_check_rx_pending(struct ol_softc *scn, int ce_id)
+{
+	struct CE_state *CE_state = scn->ce_id_to_state[ce_id];
+	if (cdf_atomic_read(&CE_state->rx_pending))
+		return true;
+	else
+		return false;
+}
+void ce_enable_msi(struct ol_softc *scn, unsigned int CE_id,
+				   uint32_t msi_addr_lo, uint32_t msi_addr_hi,
+				   uint32_t msi_data)
+{
+#ifdef WLAN_ENABLE_QCA6180
+	struct CE_state *CE_state;
+	A_target_id_t targid;
+	u_int32_t ctrl_addr;
+	uint32_t tmp;
+
+	adf_os_spin_lock(&scn->target_lock);
+	CE_state = scn->ce_id_to_state[CE_id];
+	if (!CE_state) {
+		HIF_ERROR("%s: error - CE_state = NULL", __func__);
+		adf_os_spin_unlock(&scn->target_lock);
+		return;
+	}
+	targid = TARGID(sc);
+	ctrl_addr = CE_state->ctrl_addr;
+	CE_MSI_ADDR_LOW_SET(scn, ctrl_addr, msi_addr_lo);
+	CE_MSI_ADDR_HIGH_SET(scn, ctrl_addr, msi_addr_hi);
+	CE_MSI_DATA_SET(scn, ctrl_addr, msi_data);
+	tmp = CE_CTRL_REGISTER1_GET(scn, ctrl_addr);
+	tmp |= (1 << CE_MSI_ENABLE_BIT);
+	CE_CTRL_REGISTER1_SET(scn, ctrl_addr, tmp);
+	adf_os_spin_unlock(&scn->target_lock);
+#endif
+}
+
+#ifdef IPA_OFFLOAD
+/*
+ * Copy engine should release resource to micro controller
+ * Micro controller needs
+   - Copy engine source descriptor base address
+   - Copy engine source descriptor size
+   - PCI BAR address to access copy engine regiser
+ */
+void ce_ipa_get_resource(struct CE_handle *ce,
+			 uint32_t *ce_sr_base_paddr,
+			 uint32_t *ce_sr_ring_size,
+			 cdf_dma_addr_t *ce_reg_paddr)
+{
+	struct CE_state *CE_state = (struct CE_state *)ce;
+	uint32_t ring_loop;
+	struct CE_src_desc *ce_desc;
+	cdf_dma_addr_t phy_mem_base;
+	struct ol_softc *scn = CE_state->scn;
+
+	if (CE_RUNNING != CE_state->state) {
+		*ce_sr_base_paddr = 0;
+		*ce_sr_ring_size = 0;
+		return;
+	}
+
+	/* Update default value for descriptor */
+	for (ring_loop = 0; ring_loop < CE_state->src_ring->nentries;
+	     ring_loop++) {
+		ce_desc = (struct CE_src_desc *)
+			  ((char *)CE_state->src_ring->base_addr_owner_space +
+			   ring_loop * (sizeof(struct CE_src_desc)));
+		CE_IPA_RING_INIT(ce_desc);
+	}
+
+	/* Get BAR address */
+	hif_read_phy_mem_base(CE_state->scn, &phy_mem_base);
+
+	*ce_sr_base_paddr = (uint32_t) CE_state->src_ring->base_addr_CE_space;
+	*ce_sr_ring_size = (uint32_t) CE_state->src_ring->nentries;
+	*ce_reg_paddr = phy_mem_base + CE_BASE_ADDRESS(CE_state->id) +
+			SR_WR_INDEX_ADDRESS;
+	return;
+}
+#endif /* IPA_OFFLOAD */
+
diff --git a/core/hif/src/ce/ce_tasklet.c b/core/hif/src/ce/ce_tasklet.c
new file mode 100644
index 0000000..6bb550e
--- /dev/null
+++ b/core/hif/src/ce/ce_tasklet.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#include <osdep.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/if_arp.h>
+#include "a_types.h"
+#include "athdefs.h"
+#include "cdf_lock.h"
+#include "cdf_types.h"
+#include "cdf_status.h"
+#include "cds_api.h"
+#include "regtable.h"
+#include "hif.h"
+#include "hif_io32.h"
+#include "ce_main.h"
+#include "ce_api.h"
+#include "ce_reg.h"
+#include "ce_internal.h"
+#ifdef CONFIG_CNSS
+#include <net/cnss.h>
+#ifdef HIF_PCI
+#include "icnss_stub.h"
+#else
+#include <soc/qcom/icnss.h>
+#endif /* HIF_PCI */
+#endif
+#include "hif_debug.h"
+#include "hif_napi.h"
+
+
+/**
+ * ce_irq_status() - read CE IRQ status
+ * @scn: struct ol_softc
+ * @ce_id: ce_id
+ * @host_status: host_status
+ *
+ * Return: IRQ status
+ */
+static inline void ce_irq_status(struct ol_softc *scn,
+	int ce_id, uint32_t *host_status)
+{
+	uint32_t offset = HOST_IS_ADDRESS + CE_BASE_ADDRESS(ce_id);
+
+	*host_status = hif_read32_mb(scn->mem + offset);
+}
+
+/**
+ * reschedule_ce_tasklet_work_handler() - reschedule work
+ * @ce_id: ce_id
+ *
+ * Return: N/A
+ */
+static void reschedule_ce_tasklet_work_handler(int ce_id)
+{
+	struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF);
+	struct HIF_CE_state *hif_ce_state;
+
+	if (NULL == scn) {
+		HIF_ERROR("%s: tasklet scn is null", __func__);
+		return;
+	}
+	hif_ce_state = (struct HIF_CE_state *)scn->hif_hdl;
+
+	if (scn->hif_init_done == false) {
+		HIF_ERROR("%s: wlan driver is unloaded", __func__);
+		return;
+	}
+	tasklet_schedule(&hif_ce_state->tasklets[ce_id].intr_tq);
+	return;
+}
+
+/**
+ * struct tasklet_work
+ *
+ * @id: ce_id
+ * @work: work
+ */
+struct tasklet_work {
+	enum ce_id_type id;
+	struct work_struct work;
+};
+
+static struct tasklet_work tasklet_workers[CE_ID_MAX];
+static bool work_initialized;
+
+/**
+ * work_handler() - work_handler
+ * @work: struct work_struct
+ *
+ * Return: N/A
+ */
+static void work_handler(struct work_struct *work)
+{
+	struct tasklet_work *tmp;
+
+	tmp = container_of(work, struct tasklet_work, work);
+	reschedule_ce_tasklet_work_handler(tmp->id);
+}
+
+/**
+ * init_tasklet_work() - init_tasklet_work
+ * @work: struct work_struct
+ * @work_handler: work_handler
+ *
+ * Return: N/A
+ */
+#ifdef CONFIG_CNSS
+static void init_tasklet_work(struct work_struct *work,
+	work_func_t work_handler)
+{
+	cnss_init_work(work, work_handler);
+}
+#else
+static void init_tasklet_work(struct work_struct *work,
+	work_func_t work_handler)
+{
+	INIT_WORK(work, work_handler);
+}
+#endif
+
+/**
+ * init_tasklet_workers() - init_tasklet_workers
+ *
+ * Return: N/A
+ */
+void init_tasklet_workers(void)
+{
+	uint32_t id;
+
+	for (id = 0; id < CE_ID_MAX; id++) {
+		tasklet_workers[id].id = id;
+		init_tasklet_work(&tasklet_workers[id].work, work_handler);
+	}
+	work_initialized = true;
+}
+
+#ifdef CONFIG_SLUB_DEBUG_ON
+/**
+ * ce_schedule_tasklet() - schedule ce tasklet
+ * @tasklet_entry: struct ce_tasklet_entry
+ *
+ * Return: N/A
+ */
+static inline void ce_schedule_tasklet(struct ce_tasklet_entry *tasklet_entry)
+{
+	if (work_initialized && (tasklet_entry->ce_id <= CE_ID_MAX))
+		schedule_work(&tasklet_workers[tasklet_entry->ce_id].work);
+	else
+		HIF_ERROR("%s: work_initialized = %d, ce_id = %d",
+			__func__, work_initialized, tasklet_entry->ce_id);
+}
+#else
+/**
+ * ce_schedule_tasklet() - schedule ce tasklet
+ * @tasklet_entry: struct ce_tasklet_entry
+ *
+ * Return: N/A
+ */
+static inline void ce_schedule_tasklet(struct ce_tasklet_entry *tasklet_entry)
+{
+	tasklet_schedule(&tasklet_entry->intr_tq);
+}
+#endif
+
+/**
+ * ce_tasklet() - ce_tasklet
+ * @data: data
+ *
+ * Return: N/A
+ */
+static void ce_tasklet(unsigned long data)
+{
+	struct ce_tasklet_entry *tasklet_entry =
+		(struct ce_tasklet_entry *)data;
+	struct HIF_CE_state *hif_ce_state = tasklet_entry->hif_ce_state;
+	struct ol_softc *scn = hif_ce_state->scn;
+	struct CE_state *CE_state = scn->ce_id_to_state[tasklet_entry->ce_id];
+
+	if (tasklet_entry->from_irq)
+		tasklet_entry->from_irq = false;
+
+	if (cdf_atomic_read(&scn->link_suspended)) {
+		HIF_ERROR("%s: ce %d tasklet fired after link suspend.",
+				__func__, tasklet_entry->ce_id);
+		CDF_BUG(0);
+	}
+
+	ce_per_engine_service(scn, tasklet_entry->ce_id);
+
+	if (tasklet_entry->ce_id == CE_HTT_T2H_MSG &&
+			 CE_state->lro_flush_cb != NULL) {
+		CE_state->lro_flush_cb(CE_state->lro_data);
+	}
+
+	if (ce_check_rx_pending(scn, tasklet_entry->ce_id)) {
+		/*
+		 * There are frames pending, schedule tasklet to process them.
+		 * Enable the interrupt only when there is no pending frames in
+		 * any of the Copy Engine pipes.
+		 */
+		ce_schedule_tasklet(tasklet_entry);
+		return;
+	}
+
+	if (scn->target_status != OL_TRGET_STATUS_RESET)
+		ce_irq_enable(scn, tasklet_entry->ce_id);
+
+	cdf_atomic_dec(&scn->active_tasklet_cnt);
+}
+/**
+ * ce_tasklet_init() - ce_tasklet_init
+ * @hif_ce_state: hif_ce_state
+ * @mask: mask
+ *
+ * Return: N/A
+ */
+void ce_tasklet_init(struct HIF_CE_state *hif_ce_state, uint32_t mask)
+{
+	int i;
+
+	for (i = 0; i < CE_COUNT_MAX; i++) {
+		if (mask & (1 << i)) {
+			hif_ce_state->tasklets[i].ce_id = i;
+			hif_ce_state->tasklets[i].inited = true;
+			hif_ce_state->tasklets[i].hif_ce_state = hif_ce_state;
+			tasklet_init(&hif_ce_state->tasklets[i].intr_tq,
+				ce_tasklet,
+				(unsigned long)&hif_ce_state->tasklets[i]);
+		}
+	}
+}
+/**
+ * ce_tasklet_kill() - ce_tasklet_kill
+ * @hif_ce_state: hif_ce_state
+ *
+ * Return: N/A
+ */
+void ce_tasklet_kill(struct HIF_CE_state *hif_ce_state)
+{
+	int i;
+	struct ol_softc *scn = hif_ce_state->scn;
+
+	for (i = 0; i < CE_COUNT_MAX; i++)
+		if (hif_ce_state->tasklets[i].inited) {
+			tasklet_kill(&hif_ce_state->tasklets[i].intr_tq);
+			hif_ce_state->tasklets[i].inited = false;
+		}
+	cdf_atomic_set(&scn->active_tasklet_cnt, 0);
+}
+/**
+ * ce_irq_handler() - ce_irq_handler
+ * @ce_id: ce_id
+ * @context: context
+ *
+ * Return: N/A
+ */
+static irqreturn_t ce_irq_handler(int irq, void *context)
+{
+	struct ce_tasklet_entry *tasklet_entry = context;
+	struct HIF_CE_state *hif_ce_state = tasklet_entry->hif_ce_state;
+	struct ol_softc *scn = hif_ce_state->scn;
+	int ce_id = icnss_get_ce_id(irq);
+	uint32_t host_status;
+
+
+	if (tasklet_entry->ce_id != ce_id) {
+		HIF_ERROR("%s: ce_id (expect %d, received %d) does not match",
+			  __func__, tasklet_entry->ce_id, ce_id);
+		return IRQ_NONE;
+	}
+
+#ifndef HIF_PCI
+	disable_irq_nosync(irq);
+#endif
+	ce_irq_disable(scn, ce_id);
+	ce_irq_status(scn, ce_id, &host_status);
+	cdf_atomic_inc(&scn->active_tasklet_cnt);
+	if (hif_napi_enabled(scn, ce_id))
+		hif_napi_schedule(scn, ce_id);
+	else {
+		tasklet_entry->from_irq = true;
+		tasklet_schedule(&tasklet_entry->intr_tq);
+	}
+	return IRQ_HANDLED;
+}
+
+/**
+ * const char *ce_name
+ *
+ * @ce_name: ce_name
+ */
+const char *ce_name[ICNSS_MAX_IRQ_REGISTRATIONS] = {
+	"WLAN_CE_0",
+	"WLAN_CE_1",
+	"WLAN_CE_2",
+	"WLAN_CE_3",
+	"WLAN_CE_4",
+	"WLAN_CE_5",
+	"WLAN_CE_6",
+	"WLAN_CE_7",
+	"WLAN_CE_8",
+	"WLAN_CE_9",
+	"WLAN_CE_10",
+	"WLAN_CE_11",
+};
+/**
+ * ce_unregister_irq() - ce_unregister_irq
+ * @hif_ce_state: hif_ce_state copy engine device handle
+ * @mask: which coppy engines to unregister for.
+ *
+ * Unregisters copy engine irqs matching mask.  If a 1 is set at bit x,
+ * unregister for copy engine x.
+ *
+ * Return: CDF_STATUS
+ */
+CDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask)
+{
+	int id;
+	int ret;
+
+	if (hif_ce_state == NULL) {
+		HIF_WARN("%s: hif_ce_state = NULL", __func__);
+		return CDF_STATUS_SUCCESS;
+	}
+	for (id = 0; id < CE_COUNT_MAX; id++) {
+		if ((mask & (1 << id)) && hif_ce_state->tasklets[id].inited) {
+			ret = icnss_ce_free_irq(id,
+					&hif_ce_state->tasklets[id]);
+			if (ret < 0)
+				HIF_ERROR(
+					"%s: icnss_unregister_irq error - ce_id = %d, ret = %d",
+					__func__, id, ret);
+		}
+	}
+	return CDF_STATUS_SUCCESS;
+}
+/**
+ * ce_register_irq() - ce_register_irq
+ * @hif_ce_state: hif_ce_state
+ * @mask: which coppy engines to unregister for.
+ *
+ * Registers copy engine irqs matching mask.  If a 1 is set at bit x,
+ * Register for copy engine x.
+ *
+ * Return: CDF_STATUS
+ */
+CDF_STATUS ce_register_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask)
+{
+	int id;
+	int ret;
+	unsigned long irqflags = IRQF_TRIGGER_RISING;
+	uint32_t done_mask = 0;
+
+	for (id = 0; id < CE_COUNT_MAX; id++) {
+		if ((mask & (1 << id)) && hif_ce_state->tasklets[id].inited) {
+			ret = icnss_ce_request_irq(id, ce_irq_handler,
+				irqflags, ce_name[id],
+				&hif_ce_state->tasklets[id]);
+			if (ret) {
+				HIF_ERROR(
+					"%s: cannot register CE %d irq handler, ret = %d",
+					__func__, id, ret);
+				ce_unregister_irq(hif_ce_state, done_mask);
+				return CDF_STATUS_E_FAULT;
+			} else {
+				done_mask |= 1 << id;
+			}
+		}
+	}
+
+#ifndef HIF_PCI
+	/* move to hif_configure_irq */
+	ce_enable_irq_in_group_reg(hif_ce_state->scn, done_mask);
+#endif
+
+	return CDF_STATUS_SUCCESS;
+}
diff --git a/core/hif/src/ce/ce_tasklet.h b/core/hif/src/ce/ce_tasklet.h
new file mode 100644
index 0000000..c414770
--- /dev/null
+++ b/core/hif/src/ce/ce_tasklet.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef __CE_TASKLET_H__
+#define __CE_TASKLET_H__
+void init_tasklet_workers(void);
+void ce_tasklet_init(struct HIF_CE_state *hif_ce_state, uint32_t mask);
+void ce_tasklet_kill(struct HIF_CE_state *hif_ce_state);
+CDF_STATUS ce_register_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask);
+CDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask);
+#endif /* __CE_TASKLET_H__ */