qcacmn: Add CE services changes for SRNG based target

SRNG based target uses SRNG(Standard Ring) interface to implement all
the ring related access functions. This change provides CE services to
use interact with SRNG for CE access. It uses hal_srng module for HW
related access. It implements src ring using SRNG src ring and
destination ring using dest and status ring.
fastpath and batch send is not implemented as these are not applicable
to this target

Change-Id: I3e2b613004a08d669319f956d7b0656447eb8521
CRs-Fixed: 1042915
diff --git a/hif/src/ce/ce_service_srng.c b/hif/src/ce/ce_service_srng.c
new file mode 100644
index 0000000..a1bd74f
--- /dev/null
+++ b/hif/src/ce/ce_service_srng.c
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hif.h"
+#include "hif_io32.h"
+#include "reg_struct.h"
+#include "ce_api.h"
+#include "ce_main.h"
+#include "ce_internal.h"
+#include "ce_reg.h"
+#include "qdf_lock.h"
+#include "regtable.h"
+#include "hif_main.h"
+#include "hif_debug.h"
+#include "hal_api.h"
+
+/*
+ * 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
+ * receives 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
+ */
+
+#define CE_ADDR_COPY(desc, dma_addr) do {\
+		(desc)->buffer_addr_lo = (uint32_t)((dma_addr) &\
+							  0xFFFFFFFF);\
+		(desc)->buffer_addr_hi =\
+			(uint32_t)(((dma_addr) >> 32) & 0xFF);\
+	} while (0)
+
+int
+ce_send_nolock_srng(struct CE_handle *copyeng,
+			   void *per_transfer_context,
+			   qdf_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;
+	unsigned int nentries_mask = src_ring->nentries_mask;
+	unsigned int write_index = src_ring->write_index;
+	uint64_t dma_addr = buffer;
+	struct hif_softc *scn = CE_state->scn;
+
+	if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
+		return QDF_STATUS_E_FAILURE;
+	if (unlikely(hal_srng_src_num_avail(scn->hal_soc, src_ring->srng_ctx,
+					false) <= 0)) {
+		OL_ATH_CE_PKT_ERROR_COUNT_INCR(scn, CE_RING_DELTA_FAIL);
+		Q_TARGET_ACCESS_END(scn);
+		return QDF_STATUS_E_FAILURE;
+	}
+	{
+		enum hif_ce_event_type event_type = HIF_TX_GATHER_DESC_POST;
+		struct ce_srng_src_desc *src_desc;
+
+		if (hal_srng_access_start(scn->hal_soc, src_ring->srng_ctx)) {
+			Q_TARGET_ACCESS_END(scn);
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		src_desc = hal_srng_src_get_next_reaped(scn->hal_soc,
+				src_ring->srng_ctx);
+
+		/* Update low 32 bits source descriptor address */
+		src_desc->buffer_addr_lo =
+			(uint32_t)(dma_addr & 0xFFFFFFFF);
+		src_desc->buffer_addr_hi =
+			(uint32_t)((dma_addr >> 32) & 0xFF);
+
+		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)
+		 */
+		src_desc->byte_swap =
+			(((CE_state->attr_flags & CE_ATTR_BYTE_SWAP_DATA)
+			  != 0) & ((flags & CE_SEND_FLAG_SWAP_DISABLE) == 0));
+		src_desc->gather = ((flags & CE_SEND_FLAG_GATHER) != 0);
+		src_desc->nbytes = nbytes;
+
+		src_ring->per_transfer_context[write_index] =
+			per_transfer_context;
+		write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+
+		hal_srng_access_end(scn->hal_soc, src_ring->srng_ctx);
+
+		/* src_ring->write index hasn't been updated event though
+		 * the register has allready been written to.
+		 */
+		hif_record_ce_desc_event(scn, CE_state->id, event_type,
+			(union ce_desc *) src_desc, per_transfer_context,
+			src_ring->write_index);
+
+		src_ring->write_index = write_index;
+		status = QDF_STATUS_SUCCESS;
+	}
+	Q_TARGET_ACCESS_END(scn);
+	return status;
+}
+
+int
+ce_sendlist_send_srng(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 num_items = sl->num_items;
+	unsigned int sw_index;
+	unsigned int write_index;
+	struct hif_softc *scn = CE_state->scn;
+
+	QDF_ASSERT((num_items > 0) && (num_items < src_ring->nentries));
+
+	qdf_spin_lock_bh(&CE_state->ce_index_lock);
+	sw_index = src_ring->sw_index;
+	write_index = src_ring->write_index;
+
+	if (hal_srng_src_num_avail(scn->hal_soc, src_ring->srng_ctx, false) >=
+	    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? */
+			QDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE);
+			status = ce_send_nolock_srng(copyeng,
+					CE_SENDLIST_ITEM_CTXT,
+				(qdf_dma_addr_t) item->data,
+				item->u.nbytes, transfer_id,
+				item->flags | CE_SEND_FLAG_GATHER,
+				item->user_flags);
+			QDF_ASSERT(status == QDF_STATUS_SUCCESS);
+		}
+		/* provide valid context pointer for final item */
+		item = &sl->item[i];
+		/* TBDXXX: Support extensible sendlist_types? */
+		QDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE);
+		status = ce_send_nolock_srng(copyeng, per_transfer_context,
+					(qdf_dma_addr_t) item->data,
+					item->u.nbytes,
+					transfer_id, item->flags,
+					item->user_flags);
+		QDF_ASSERT(status == QDF_STATUS_SUCCESS);
+		QDF_NBUF_UPDATE_TX_PKT_COUNT((qdf_nbuf_t)per_transfer_context,
+					QDF_NBUF_TX_PKT_CE);
+		DPTRACE(qdf_dp_trace((qdf_nbuf_t)per_transfer_context,
+			QDF_DP_TRACE_CE_PACKET_PTR_RECORD,
+			(uint8_t *)(((qdf_nbuf_t)per_transfer_context)->data),
+			sizeof(((qdf_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.
+		 */
+	}
+	qdf_spin_unlock_bh(&CE_state->ce_index_lock);
+
+	return status;
+}
+
+#define SLOTS_PER_DATAPATH_TX 2
+
+#ifndef AH_NEED_TX_DATA_SWAP
+#define AH_NEED_TX_DATA_SWAP 0
+#endif
+/**
+ * ce_recv_buf_enqueue_srng() - enqueue a recv buffer into a copy engine
+ * @coyeng: copy engine handle
+ * @per_recv_context: virtual address of the nbuf
+ * @buffer: physical address of the nbuf
+ *
+ * Return: 0 if the buffer is enqueued
+ */
+int
+ce_recv_buf_enqueue_srng(struct CE_handle *copyeng,
+		    void *per_recv_context, qdf_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;
+	unsigned int nentries_mask = dest_ring->nentries_mask;
+	unsigned int write_index;
+	unsigned int sw_index;
+	uint64_t dma_addr = buffer;
+	struct hif_softc *scn = CE_state->scn;
+
+	qdf_spin_lock_bh(&CE_state->ce_index_lock);
+	write_index = dest_ring->write_index;
+	sw_index = dest_ring->sw_index;
+
+	if (Q_TARGET_ACCESS_BEGIN(scn) < 0) {
+		qdf_spin_unlock_bh(&CE_state->ce_index_lock);
+		return -EIO;
+	}
+
+	if (hal_srng_access_start(scn->hal_soc, dest_ring->srng_ctx)) {
+		qdf_spin_unlock_bh(&CE_state->ce_index_lock);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if ((hal_srng_src_num_avail(scn->hal_soc,
+					dest_ring->srng_ctx, false) > 0)) {
+		struct ce_srng_dest_desc *dest_desc =
+				hal_srng_src_get_next(scn->hal_soc,
+							dest_ring->srng_ctx);
+
+		if (dest_desc == NULL) {
+			status = QDF_STATUS_E_FAILURE;
+		} else {
+
+			CE_ADDR_COPY(dest_desc, dma_addr);
+
+			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);
+			status = QDF_STATUS_SUCCESS;
+		}
+	} else
+		status = QDF_STATUS_E_FAILURE;
+
+	dest_ring->write_index = write_index;
+	hal_srng_access_end(scn->hal_soc, dest_ring->srng_ctx);
+	Q_TARGET_ACCESS_END(scn);
+	qdf_spin_unlock_bh(&CE_state->ce_index_lock);
+	return status;
+}
+
+/**
+ * ce_send_watermarks_set_srng
+ */
+void
+ce_send_watermarks_set_srng(struct CE_handle *copyeng,
+		       unsigned int low_alert_nentries,
+		       unsigned int high_alert_nentries)
+{
+	/*TODO*/
+}
+/*
+ * ce_recv_watermarks_set_srng
+ */
+void
+ce_recv_watermarks_set_srng(struct CE_handle *copyeng,
+		       unsigned int low_alert_nentries,
+		       unsigned int high_alert_nentries)
+{
+	/*TODO*/
+}
+
+unsigned int ce_send_entries_avail_srng(struct CE_handle *copyeng)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	struct CE_ring_state *src_ring = CE_state->src_ring;
+	struct hif_softc *scn = CE_state->scn;
+
+	return hal_srng_src_num_avail(scn->hal_soc, src_ring->srng_ctx, false);
+}
+
+unsigned int ce_recv_entries_avail_srng(struct CE_handle *copyeng)
+{
+	struct CE_state *CE_state = (struct CE_state *)copyeng;
+	struct CE_ring_state *dest_ring = CE_state->dest_ring;
+	struct hif_softc *scn = CE_state->scn;
+
+
+	return hal_srng_src_num_avail(scn->hal_soc, dest_ring->srng_ctx, false);
+}
+
+/*
+ * Guts of ce_recv_entries_done.
+ * The caller takes responsibility for any necessary locking.
+ */
+unsigned int
+ce_recv_entries_done_nolock_srng(struct hif_softc *scn,
+			    struct CE_state *CE_state)
+{
+	struct CE_ring_state *status_ring = CE_state->status_ring;
+
+	return hal_srng_dst_num_valid(scn->hal_soc,
+				status_ring->srng_ctx, false);
+}
+
+/*
+ * Guts of ce_send_entries_done.
+ * The caller takes responsibility for any necessary locking.
+ */
+unsigned int
+ce_send_entries_done_nolock_srng(struct hif_softc *scn,
+					struct CE_state *CE_state)
+{
+
+	struct CE_ring_state *src_ring = CE_state->src_ring;
+	int count = 0;
+
+	if (hal_srng_access_start(scn->hal_soc, src_ring->srng_ctx))
+		return 0;
+
+	count = hal_srng_src_done_val(scn->hal_soc, src_ring->srng_ctx);
+
+	hal_srng_access_end(scn->hal_soc, src_ring->srng_ctx);
+
+	return count;
+}
+
+/* Debug support */
+void *ce_debug_cmplrn_context_srng;  /* completed recv next context */
+void *ce_debug_cmplsn_context_srng;  /* completed send next context */
+
+/*
+ * Guts of ce_completed_recv_next.
+ * The caller takes responsibility for any necessary locking.
+ */
+int
+ce_completed_recv_next_nolock_srng(struct CE_state *CE_state,
+			      void **per_CE_contextp,
+			      void **per_transfer_contextp,
+			      qdf_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;
+	struct CE_ring_state *status_ring = CE_state->status_ring;
+	unsigned int nentries_mask = dest_ring->nentries_mask;
+	unsigned int sw_index = dest_ring->sw_index;
+	struct hif_softc *scn = CE_state->scn;
+	struct ce_srng_dest_status_desc *dest_status;
+	int nbytes;
+	struct ce_srng_dest_status_desc dest_status_info;
+
+	if (hal_srng_access_start(scn->hal_soc, status_ring->srng_ctx)) {
+		status = QDF_STATUS_E_FAILURE;
+		goto done;
+	}
+
+	dest_status = hal_srng_dst_get_next(scn->hal_soc,
+						status_ring->srng_ctx);
+
+	if (dest_status == NULL) {
+		status = QDF_STATUS_E_FAILURE;
+		goto done;
+	}
+	/*
+	 * By copying the dest_desc_info element to local memory, we could
+	 * avoid extra memory read from non-cachable memory.
+	 */
+	dest_status_info = *dest_status;
+	nbytes = dest_status_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 = QDF_STATUS_E_FAILURE;
+		goto done;
+	}
+
+	dest_status->nbytes = 0;
+
+	*nbytesp = nbytes;
+	*transfer_idp = dest_status_info.meta_data;
+	*flagsp = (dest_status_info.byte_swap) ? CE_RECV_FLAG_SWAPPED : 0;
+
+	if (per_CE_contextp)
+		*per_CE_contextp = CE_state->recv_context;
+
+	/* NOTE: sw_index is more like a read_index in this context. It has a
+	 * one-to-one mapping with status ring.
+	 * Get the per trasnfer context from dest_ring.
+	 */
+	ce_debug_cmplrn_context_srng =
+			dest_ring->per_transfer_context[sw_index];
+
+	if (per_transfer_contextp)
+		*per_transfer_contextp = ce_debug_cmplrn_context_srng;
+
+	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 = QDF_STATUS_SUCCESS;
+
+done:
+	hal_srng_access_end(scn->hal_soc, status_ring->srng_ctx);
+
+	return status;
+}
+
+QDF_STATUS
+ce_revoke_recv_next_srng(struct CE_handle *copyeng,
+		    void **per_CE_contextp,
+		    void **per_transfer_contextp, qdf_dma_addr_t *bufferp)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	return status;
+}
+
+/*
+ * Guts of ce_completed_send_next.
+ * The caller takes responsibility for any necessary locking.
+ */
+int
+ce_completed_send_next_nolock_srng(struct CE_state *CE_state,
+			      void **per_CE_contextp,
+			      void **per_transfer_contextp,
+			      qdf_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 = QDF_STATUS_E_FAILURE;
+	struct CE_ring_state *src_ring = CE_state->src_ring;
+	unsigned int nentries_mask = src_ring->nentries_mask;
+	unsigned int sw_index = src_ring->sw_index;
+	struct hif_softc *scn = CE_state->scn;
+	struct ce_srng_src_desc *src_desc;
+
+	if (hal_srng_access_start(scn->hal_soc, src_ring->srng_ctx)) {
+		status = QDF_STATUS_E_FAILURE;
+		return status;
+	}
+
+	src_desc = hal_srng_src_reap_next(scn->hal_soc, src_ring->srng_ctx);
+	if (src_desc) {
+
+		/* Return data from completed source descriptor */
+		*bufferp = (qdf_dma_addr_t)
+			(((uint64_t)(src_desc)->buffer_addr_lo +
+			  ((uint64_t)((src_desc)->buffer_addr_hi &
+				  0xFF) << 32)));
+		*nbytesp = src_desc->nbytes;
+		*transfer_idp = src_desc->meta_data;
+		*toeplitz_hash_result = 0; /*src_desc->toeplitz_hash_result;*/
+
+		if (per_CE_contextp)
+			*per_CE_contextp = CE_state->send_context;
+
+		/* sw_index is used more like read index */
+		ce_debug_cmplsn_context_srng =
+			src_ring->per_transfer_context[sw_index];
+		if (per_transfer_contextp)
+			*per_transfer_contextp = ce_debug_cmplsn_context_srng;
+
+		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 = QDF_STATUS_SUCCESS;
+	}
+	hal_srng_access_end(scn->hal_soc, src_ring->srng_ctx);
+
+	return status;
+}
+
+/* NB: Modelled after ce_completed_send_next */
+QDF_STATUS
+ce_cancel_send_next_srng(struct CE_handle *copyeng,
+		void **per_CE_contextp,
+		void **per_transfer_contextp,
+		qdf_dma_addr_t *bufferp,
+		unsigned int *nbytesp,
+		unsigned int *transfer_idp,
+		uint32_t *toeplitz_hash_result)
+{
+	return 0;
+}
+
+/* Shift bits to convert IS_*_RING_*_WATERMARK_MASK to CE_WM_FLAG_*_* */
+#define CE_WM_SHFT 1
+
+/*
+ * 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
+
+/*
+ * 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_srng(struct CE_state *CE_state,
+			     int disable_copy_compl_intr)
+{
+}
+
+bool ce_check_int_watermark_srng(struct CE_state *CE_state, unsigned int *flags)
+{
+	/*TODO*/
+	return false;
+}
+
+uint32_t ce_get_desc_size_srng(uint8_t ring_type)
+{
+	switch (ring_type) {
+	case CE_RING_SRC:
+		return sizeof(struct ce_srng_src_desc);
+	case CE_RING_DEST:
+		return sizeof(struct ce_srng_dest_desc);
+	case CE_RING_STATUS:
+		return sizeof(struct ce_srng_dest_status_desc);
+	default:
+		return 0;
+	}
+	return 0;
+}
+
+void ce_srng_src_ring_setup(struct hif_softc *scn, uint32_t ce_id,
+			struct CE_ring_state *src_ring)
+{
+	struct hal_srng_params ring_params = {0};
+
+	ring_params.ring_base_paddr = src_ring->base_addr_CE_space;
+	ring_params.ring_base_vaddr = src_ring->base_addr_owner_space;
+	ring_params.num_entries = src_ring->nentries;
+	ring_params.intr_timer_thres_us = 4;
+	ring_params.intr_batch_cntr_thres_entries = 1;
+
+	/* TODO
+	 * ring_params.msi_addr = XXX;
+	 * ring_params.msi_data = XXX;
+	 * ring_params.flags = XXX;
+	 */
+
+	src_ring->srng_ctx = hal_srng_setup(scn->hal_soc, CE_SRC, ce_id, 0,
+			&ring_params);
+}
+
+void ce_srng_dest_ring_setup(struct hif_softc *scn, uint32_t ce_id,
+				struct CE_ring_state *dest_ring)
+{
+	struct hal_srng_params ring_params = {0};
+
+	ring_params.ring_base_paddr = dest_ring->base_addr_CE_space;
+	ring_params.ring_base_vaddr = dest_ring->base_addr_owner_space;
+	ring_params.num_entries = dest_ring->nentries;
+	ring_params.intr_timer_thres_us = 4;
+	ring_params.intr_batch_cntr_thres_entries = 1;
+
+	/* TODO
+	 * ring_params.msi_addr = XXX;
+	 * ring_params.msi_data = XXX;
+	 * ring_params.flags = XXX;
+	 */
+
+	/*Dest ring is also source ring*/
+	dest_ring->srng_ctx = hal_srng_setup(scn->hal_soc, CE_DST, ce_id, 0,
+			&ring_params);
+}
+
+void ce_srng_status_ring_setup(struct hif_softc *scn, uint32_t ce_id,
+				struct CE_ring_state *status_ring)
+{
+	struct hal_srng_params ring_params = {0};
+
+	ring_params.ring_base_paddr = status_ring->base_addr_CE_space;
+	ring_params.ring_base_vaddr = status_ring->base_addr_owner_space;
+	ring_params.num_entries = status_ring->nentries;
+	ring_params.intr_timer_thres_us = 4;
+	ring_params.intr_batch_cntr_thres_entries = 1;
+
+	/* TODO
+	 * ring_params.msi_addr = XXX;
+	 * ring_params.msi_data = XXX;
+	 * ring_params.flags = XXX;
+	 */
+
+	status_ring->srng_ctx = hal_srng_setup(scn->hal_soc, CE_DST_STATUS,
+			ce_id, 0, &ring_params);
+}
+
+void ce_ring_setup_srng(struct hif_softc *scn, uint8_t ring_type,
+		uint32_t ce_id, struct CE_ring_state *ring,
+		struct CE_attr *attr)
+{
+	switch (ring_type) {
+	case CE_RING_SRC:
+		ce_srng_src_ring_setup(scn, ce_id, ring);
+		break;
+	case CE_RING_DEST:
+		ce_srng_dest_ring_setup(scn, ce_id, ring);
+		break;
+	case CE_RING_STATUS:
+		ce_srng_status_ring_setup(scn, ce_id, ring);
+		break;
+	default:
+		qdf_assert(0);
+		break;
+	}
+}
+struct ce_ops ce_service_srng = {
+	.ce_get_desc_size = ce_get_desc_size_srng,
+	.ce_ring_setup = ce_ring_setup_srng,
+	.ce_sendlist_send = ce_sendlist_send_srng,
+	.ce_completed_recv_next_nolock = ce_completed_recv_next_nolock_srng,
+	.ce_revoke_recv_next = ce_revoke_recv_next_srng,
+	.ce_cancel_send_next = ce_cancel_send_next_srng,
+	.ce_recv_buf_enqueue = ce_recv_buf_enqueue_srng,
+	.ce_per_engine_handler_adjust = ce_per_engine_handler_adjust_srng,
+	.ce_send_nolock = ce_send_nolock_srng,
+	.watermark_int = ce_check_int_watermark_srng,
+	.ce_completed_send_next_nolock = ce_completed_send_next_nolock_srng,
+	.ce_recv_entries_done_nolock = ce_recv_entries_done_nolock_srng,
+	.ce_send_entries_done_nolock = ce_send_entries_done_nolock_srng,
+};
+
+struct ce_ops *ce_services_srng()
+{
+	return &ce_service_srng;
+}