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

Commit 6ff0d438 authored by Amir Levy's avatar Amir Levy Committed by Gerrit - the friendly Code Review server
Browse files

msm: ipa4: remove deprecated code



Remove wdi3 over uC offload code and also NTN_ERROR event.
Both are now deprecated at IPA uC side.

CRs-Fixed: 2337876
Change-Id: I8722a90189cefe1f6ff030747f84479922ff6e95
Signed-off-by: default avatarAmir Levy <alevy@codeaurora.org>
parent be6924f0
Loading
Loading
Loading
Loading
+0 −17
Original line number Diff line number Diff line
@@ -8,22 +8,6 @@
#define IPA_UC_NTN_DB_PA_TX 0x79620DC
#define IPA_UC_NTN_DB_PA_RX 0x79620D8

static void ipa3_uc_ntn_event_handler(struct IpaHwSharedMemCommonMapping_t
				     *uc_sram_mmio)

{
	union Ipa3HwNTNErrorEventData_t ntn_evt;

	if (uc_sram_mmio->eventOp ==
		IPA_HW_2_CPU_EVENT_NTN_ERROR) {
		ntn_evt.raw32b = uc_sram_mmio->eventParams;
		IPADBG("uC NTN evt errType=%u pipe=%d cherrType=%u\n",
			   ntn_evt.params.ntn_error_type,
			   ntn_evt.params.ipa_pipe_number,
			   ntn_evt.params.ntn_ch_err_type);
	}
}

static void ipa3_uc_ntn_event_log_info_handler(
struct IpaHwEventLogInfoData_t *uc_event_top_mmio)
{
@@ -179,7 +163,6 @@ int ipa3_ntn_init(void)
{
	struct ipa3_uc_hdlrs uc_ntn_cbs = { 0 };

	uc_ntn_cbs.ipa_uc_event_hdlr = ipa3_uc_ntn_event_handler;
	uc_ntn_cbs.ipa_uc_event_log_info_hdlr =
		ipa3_uc_ntn_event_log_info_handler;
	uc_ntn_cbs.ipa_uc_loaded_hdlr =
+0 −102
Original line number Diff line number Diff line
@@ -19,9 +19,6 @@
#define IPA_NTN_TX_DIR 1
#define IPA_NTN_RX_DIR 2

#define IPA_WDI3_TX_DIR 1
#define IPA_WDI3_RX_DIR 2

/**
 *  @brief   Enum value determined based on the feature it
 *           corresponds to
@@ -46,7 +43,6 @@
 * @IPA_HW_FEATURE_WDI : Feature related to WDI operation in IPA HW
 * @IPA_HW_FEATURE_NTN : Feature related to NTN operation in IPA HW
 * @IPA_HW_FEATURE_OFFLOAD : Feature related to NTN operation in IPA HW
 * @IPA_HW_FEATURE_WDI3 : Feature related to WDI operation in IPA HW
 */
enum ipa3_hw_features {
	IPA_HW_FEATURE_COMMON		=	0x0,
@@ -56,7 +52,6 @@ enum ipa3_hw_features {
	IPA_HW_FEATURE_ZIP		=	0x4,
	IPA_HW_FEATURE_NTN		=	0x5,
	IPA_HW_FEATURE_OFFLOAD		=	0x6,
	IPA_HW_FEATURE_WDI3		=	0x7,
	IPA_HW_FEATURE_MAX		=	IPA_HW_NUM_FEATURES
};

@@ -244,29 +239,6 @@ struct ipa3_uc_ntn_ctx {
	ipa_uc_ready_cb uc_ready_cb;
};

/**
 * enum ipa3_hw_2_cpu_ntn_events - Values that represent HW event
 *			to be sent to CPU
 * @IPA_HW_2_CPU_EVENT_NTN_ERROR : Event to specify that HW
 *			detected an error in NTN
 *
 */
enum ipa3_hw_2_cpu_ntn_events {
	IPA_HW_2_CPU_EVENT_NTN_ERROR =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_NTN, 0),
};


/**
 * enum ipa3_hw_ntn_errors - NTN specific error types.
 * @IPA_HW_NTN_ERROR_NONE : No error persists
 * @IPA_HW_NTN_CHANNEL_ERROR : Error is specific to channel
 */
enum ipa3_hw_ntn_errors {
	IPA_HW_NTN_ERROR_NONE    = 0,
	IPA_HW_NTN_CHANNEL_ERROR = 1
};

/**
 * enum ipa3_hw_ntn_channel_states - Values that represent NTN
 * channel state machine.
@@ -346,33 +318,6 @@ struct Ipa3HwNtnSetUpCmdData_t {

} __packed;

struct IpaHwWdi3SetUpCmdData_t {
	u32  transfer_ring_base_pa;
	u32  transfer_ring_base_pa_hi;

	u32  transfer_ring_size;

	u32  transfer_ring_doorbell_pa;
	u32  transfer_ring_doorbell_pa_hi;

	u32  event_ring_base_pa;
	u32  event_ring_base_pa_hi;

	u32  event_ring_size;

	u32  event_ring_doorbell_pa;
	u32  event_ring_doorbell_pa_hi;

	u16  num_pkt_buffers;
	u8   ipa_pipe_number;
	u8   dir;

	u16  pkt_offset;
	u16  reserved0;

	u32  desc_format_template[IPA_HW_WDI3_MAX_ER_DESC_SIZE];
} __packed;

/**
 * struct Ipa3HwNtnCommonChCmdData_t - Structure holding the
 * parameters for Ntn Tear down command data params
@@ -387,35 +332,6 @@ union Ipa3HwNtnCommonChCmdData_t {
	uint32_t raw32b;
} __packed;

union IpaHwWdi3CommonChCmdData_t {
	struct IpaHwWdi3CommonChCmdParams_t {
		u32  ipa_pipe_number :8;
		u32  reserved        :24;
	} __packed params;
	u32 raw32b;
} __packed;

/**
 * struct Ipa3HwNTNErrorEventData_t - Structure holding the
 * IPA_HW_2_CPU_EVENT_NTN_ERROR event. The parameters are passed
 * as immediate params in the shared memory
 *
 *@ntn_error_type: type of NTN error (ipa3_hw_ntn_errors)
 *@ipa_pipe_number: IPA pipe number on which error has happened
 *   Applicable only if error type indicates channel error
 *@ntn_ch_err_type: Information about the channel error (if
 *		available)
 */
union Ipa3HwNTNErrorEventData_t {
	struct IpaHwNTNErrorEventParams_t {
		u32  ntn_error_type  :8;
		u32  reserved        :8;
		u32  ipa_pipe_number :8;
		u32  ntn_ch_err_type :8;
	} __packed params;
	uint32_t raw32b;
} __packed;

/**
 * struct NTN3RxInfoData_t - NTN Structure holding the Rx pipe
 * information
@@ -486,28 +402,12 @@ struct Ipa3HwStatsNTNInfoData_t {
 *				Offload protocol's Tx/Rx Path
 * @IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN : Command to tear down
 *				Offload protocol's Tx/ Rx Path
 * @IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE : Command to enable
 *				Offload protocol's Tx/Rx Path
 * @IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE : Command to disable
 *				Offload protocol's Tx/ Rx Path
 * @IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND : Command to suspend
 *				Offload protocol's Tx/Rx Path
 * @IPA_CPU_2_HW_CMD_OFFLOAD_RESUME : Command to resume
 *				Offload protocol's Tx/ Rx Path
 */
enum ipa_cpu_2_hw_offload_commands {
	IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP  =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 1),
	IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 2),
	IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE  =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 3),
	IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 4),
	IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND  =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 5),
	IPA_CPU_2_HW_CMD_OFFLOAD_RESUME =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_OFFLOAD, 6),
};


@@ -577,7 +477,6 @@ enum ipa3_hw_2_cpu_offload_cmd_resp_status {
 */
union IpaHwSetUpCmd {
	struct Ipa3HwNtnSetUpCmdData_t NtnSetupCh_params;
	struct IpaHwWdi3SetUpCmdData_t Wdi3SetupCh_params;
} __packed;

/**
@@ -608,7 +507,6 @@ struct IpaHwOffloadSetUpCmdData_t_v4_0 {
 */
union IpaHwCommonChCmd {
	union Ipa3HwNtnCommonChCmdData_t NtnCommonCh_params;
	union IpaHwWdi3CommonChCmdData_t Wdi3CommonCh_params;
} __packed;

struct IpaHwOffloadCommonChCmdData_t {
+12 −531
Original line number Diff line number Diff line
@@ -6,555 +6,36 @@
#include "ipa_i.h"
#include <linux/ipa_wdi3.h>

#define IPA_HW_WDI3_RX_MBOX_START_INDEX 48
#define IPA_HW_WDI3_TX_MBOX_START_INDEX 50

static int ipa3_send_wdi3_setup_pipe_cmd(
	u8 is_smmu_enabled, struct ipa_wdi_pipe_setup_info *info,
	struct ipa_wdi_pipe_setup_info_smmu *info_smmu, u8 dir)
{
	int ipa_ep_idx;
	int result = 0, len;
	unsigned long va;
	struct ipa_mem_buffer cmd;
	struct IpaHwWdi3SetUpCmdData_t *wdi3_params;
	struct IpaHwOffloadSetUpCmdData_t *cmd_data;

	if (info == NULL || info_smmu == NULL) {
		IPAERR("invalid input\n");
		return -EINVAL;
	}

	cmd.size = sizeof(*cmd_data);
	cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
			&cmd.phys_base, GFP_KERNEL);
	if (cmd.base == NULL) {
		IPAERR("fail to get DMA memory.\n");
		return -ENOMEM;
	}

	cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
	cmd_data->protocol = IPA_HW_FEATURE_WDI3;

	if (!is_smmu_enabled) {
		ipa_ep_idx = ipa_get_ep_mapping(info->client);
		if (ipa_ep_idx == -1) {
			IPAERR("fail to get ep idx.\n");
			return -EFAULT;
		}

		IPADBG("client=%d ep=%d\n", info->client, ipa_ep_idx);
		IPADBG("ring_base_pa = 0x%pad\n", &info->transfer_ring_base_pa);
		IPADBG("ring_size = %hu\n", info->transfer_ring_size);
		IPADBG("ring_db_pa = 0x%pad\n",
			&info->transfer_ring_doorbell_pa);
		IPADBG("evt_ring_base_pa = 0x%pad\n",
			&info->event_ring_base_pa);
		IPADBG("evt_ring_size = %hu\n", info->event_ring_size);
		IPADBG("evt_ring_db_pa = 0x%pad\n",
			&info->event_ring_doorbell_pa);
		IPADBG("num_pkt_buffers = %hu\n", info->num_pkt_buffers);
		IPADBG("pkt_offset = %d\n", info->pkt_offset);

		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;
		wdi3_params->transfer_ring_base_pa =
			(u32)info->transfer_ring_base_pa;
		wdi3_params->transfer_ring_base_pa_hi =
			(u32)((u64)info->transfer_ring_base_pa >> 32);
		wdi3_params->transfer_ring_size = info->transfer_ring_size;
		wdi3_params->transfer_ring_doorbell_pa =
			(u32)info->transfer_ring_doorbell_pa;
		wdi3_params->transfer_ring_doorbell_pa_hi =
			(u32)((u64)info->transfer_ring_doorbell_pa >> 32);
		wdi3_params->event_ring_base_pa = (u32)info->event_ring_base_pa;
		wdi3_params->event_ring_base_pa_hi =
			(u32)((u64)info->event_ring_base_pa >> 32);
		wdi3_params->event_ring_size = info->event_ring_size;
		wdi3_params->event_ring_doorbell_pa =
			(u32)info->event_ring_doorbell_pa;
		wdi3_params->event_ring_doorbell_pa_hi =
			(u32)((u64)info->event_ring_doorbell_pa >> 32);
		wdi3_params->num_pkt_buffers = info->num_pkt_buffers;
		wdi3_params->ipa_pipe_number = ipa_ep_idx;
		wdi3_params->dir = dir;
		wdi3_params->pkt_offset = info->pkt_offset;
		memcpy(wdi3_params->desc_format_template,
			info->desc_format_template,
			sizeof(wdi3_params->desc_format_template));
	} else {
		ipa_ep_idx = ipa_get_ep_mapping(info_smmu->client);
		if (ipa_ep_idx == -1) {
			IPAERR("fail to get ep idx.\n");
			return -EFAULT;
		}

		IPADBG("client=%d ep=%d\n", info_smmu->client, ipa_ep_idx);
		IPADBG("ring_size = %hu\n", info_smmu->transfer_ring_size);
		IPADBG("ring_db_pa = 0x%pad\n",
			&info_smmu->transfer_ring_doorbell_pa);
		IPADBG("evt_ring_size = %hu\n", info_smmu->event_ring_size);
		IPADBG("evt_ring_db_pa = 0x%pad\n",
			&info_smmu->event_ring_doorbell_pa);
		IPADBG("num_pkt_buffers = %hu\n", info_smmu->num_pkt_buffers);
		IPADBG("pkt_offset = %d\n", info_smmu->pkt_offset);

		wdi3_params = &cmd_data->SetupCh_params.Wdi3SetupCh_params;

		if (dir == IPA_WDI3_TX_DIR) {
			len = info_smmu->transfer_ring_size;
			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_RING_RES,
				true, info->transfer_ring_base_pa,
				&info_smmu->transfer_ring_base, len,
				false, &va)) {
				IPAERR("failed to get smmu mapping\n");
				return -EFAULT;
			}
			wdi3_params->transfer_ring_base_pa = (u32)va;
			wdi3_params->transfer_ring_base_pa_hi =
				(u32)((u64)va >> 32);
			wdi3_params->transfer_ring_size = len;

			if (ipa_create_uc_smmu_mapping(IPA_WDI_TX_DB_RES,
				true, info_smmu->transfer_ring_doorbell_pa,
				NULL, 4, true, &va)) {
				IPAERR("failed to get smmu mapping\n");
				return -EFAULT;
			}
			wdi3_params->transfer_ring_doorbell_pa =
				(u32)va;
			wdi3_params->transfer_ring_doorbell_pa_hi =
				(u32)((u64)va >> 32);

			len = info_smmu->event_ring_size;
			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_RING_RES,
				true, info->event_ring_base_pa,
				&info_smmu->event_ring_base, len,
				false, &va)) {
				IPAERR("failed to get smmu mapping\n");
				return -EFAULT;
			}
			wdi3_params->event_ring_base_pa = (u32)va;
			wdi3_params->event_ring_base_pa_hi =
				(u32)((u64)va >> 32);
			wdi3_params->event_ring_size = len;

			if (ipa_create_uc_smmu_mapping(IPA_WDI_CE_DB_RES,
				true, info_smmu->event_ring_doorbell_pa,
				NULL, 4, true, &va)) {
				IPAERR("failed to get smmu mapping\n");
				return -EFAULT;
			}
			wdi3_params->event_ring_doorbell_pa =
				(u32)va;
			wdi3_params->event_ring_doorbell_pa_hi =
				(u32)((u64)va >> 32);
		} else {
			len = info_smmu->transfer_ring_size;
			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RES,
				true, info->transfer_ring_base_pa,
				&info_smmu->transfer_ring_base, len,
				false, &va)) {
				IPAERR("failed to get smmu mapping\n");
				return -EFAULT;
			}
			wdi3_params->transfer_ring_base_pa = (u32)va;
			wdi3_params->transfer_ring_base_pa_hi =
				(u32)((u64)va >> 32);
			wdi3_params->transfer_ring_size = len;

			if (ipa_create_uc_smmu_mapping(IPA_WDI_RX_RING_RP_RES,
				true, info_smmu->transfer_ring_doorbell_pa,
				NULL, 4, true, &va)) {
				IPAERR("failed to get smmu mapping\n");
				return -EFAULT;
			}
			wdi3_params->transfer_ring_doorbell_pa =
				(u32)va;
			wdi3_params->transfer_ring_doorbell_pa_hi =
				(u32)((u64)va >> 32);

			len = info_smmu->event_ring_size;
			if (ipa_create_uc_smmu_mapping(
				IPA_WDI_RX_COMP_RING_RES, true,
				info->event_ring_base_pa,
				&info_smmu->event_ring_base, len,
				false, &va)) {
				IPAERR("failed to get smmu mapping\n");
				return -EFAULT;
			}
			wdi3_params->event_ring_base_pa = (u32)va;
			wdi3_params->event_ring_base_pa_hi =
				(u32)((u64)va >> 32);
			wdi3_params->event_ring_size = len;

			if (ipa_create_uc_smmu_mapping(
				IPA_WDI_RX_COMP_RING_WP_RES, true,
				info_smmu->event_ring_doorbell_pa,
				NULL, 4, true, &va)) {
				IPAERR("failed to get smmu mapping\n");
				return -EFAULT;
			}
			wdi3_params->event_ring_doorbell_pa =
				(u32)va;
			wdi3_params->event_ring_doorbell_pa_hi =
				(u32)((u64)va >> 32);
		}
		wdi3_params->num_pkt_buffers = info_smmu->num_pkt_buffers;
		wdi3_params->ipa_pipe_number = ipa_ep_idx;
		wdi3_params->dir = dir;
		wdi3_params->pkt_offset = info_smmu->pkt_offset;
		memcpy(wdi3_params->desc_format_template,
			info_smmu->desc_format_template,
			sizeof(wdi3_params->desc_format_template));
	}

	result = ipa3_uc_send_cmd((u32)(cmd.phys_base),
				IPA_CPU_2_HW_CMD_OFFLOAD_CHANNEL_SET_UP,
				IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS,
				false, 10*HZ);
	if (result) {
		IPAERR("uc setup channel cmd failed: %d\n", result);
		result = -EFAULT;
	}

	dma_free_coherent(ipa3_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base);
	return result;
}

int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
	struct ipa_wdi_conn_out_params *out,
	ipa_wdi_meter_notifier_cb wdi_notify)
{
	enum ipa_client_type rx_client;
	enum ipa_client_type tx_client;
	struct ipa3_ep_context *ep_rx;
	struct ipa3_ep_context *ep_tx;
	int ipa_ep_idx_rx;
	int ipa_ep_idx_tx;
	int result = 0;

	if (in == NULL || out == NULL) {
		IPAERR("invalid input\n");
		return -EINVAL;
	}

	if (in->is_smmu_enabled == false) {
		rx_client = in->u_rx.rx.client;
		tx_client = in->u_tx.tx.client;
	} else {
		rx_client = in->u_rx.rx_smmu.client;
		tx_client = in->u_tx.tx_smmu.client;
	}

	ipa_ep_idx_rx = ipa_get_ep_mapping(rx_client);
	ipa_ep_idx_tx = ipa_get_ep_mapping(tx_client);

	if (ipa_ep_idx_rx == -1 || ipa_ep_idx_tx == -1) {
		IPAERR("fail to alloc EP.\n");
		return -EFAULT;
	}
	if (ipa_ep_idx_rx >= IPA3_MAX_NUM_PIPES ||
		ipa_ep_idx_tx >= IPA3_MAX_NUM_PIPES) {
		IPAERR("ep out of range.\n");
		return -EFAULT;
	}

	ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx];
	ep_tx = &ipa3_ctx->ep[ipa_ep_idx_tx];

	if (ep_rx->valid || ep_tx->valid) {
		IPAERR("EP already allocated.\n");
		return -EFAULT;
	}

	memset(ep_rx, 0, offsetof(struct ipa3_ep_context, sys));
	memset(ep_tx, 0, offsetof(struct ipa3_ep_context, sys));

	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
	IPAERR("wdi3 over uc offload not supported");
	WARN_ON(1);

#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
	if (wdi_notify)
		ipa3_ctx->uc_wdi_ctx.stats_notify = wdi_notify;
	else
		IPADBG("wdi_notify is null\n");
#endif

	/* setup rx ep cfg */
	ep_rx->valid = 1;
	ep_rx->client = rx_client;
	result = ipa3_disable_data_path(ipa_ep_idx_rx);
	if (result) {
		IPAERR("disable data path failed res=%d clnt=%d.\n", result,
			ipa_ep_idx_rx);
		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
	return -EFAULT;
}
	ep_rx->client_notify = in->notify;
	ep_rx->priv = in->priv;

	if (in->is_smmu_enabled == false)
		memcpy(&ep_rx->cfg, &in->u_rx.rx.ipa_ep_cfg,
			sizeof(ep_rx->cfg));
	else
		memcpy(&ep_rx->cfg, &in->u_rx.rx_smmu.ipa_ep_cfg,
			sizeof(ep_rx->cfg));

	if (ipa3_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) {
		IPAERR("fail to setup rx pipe cfg\n");
		result = -EFAULT;
		goto fail;
	}

	if (ipa3_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
		&in->u_rx.rx, &in->u_rx.rx_smmu, IPA_WDI3_RX_DIR)) {
		IPAERR("fail to send cmd to uc for rx pipe\n");
		result = -EFAULT;
		goto fail;
	}
	ipa3_install_dflt_flt_rules(ipa_ep_idx_rx);
	out->rx_uc_db_pa = ipa3_ctx->ipa_wrapper_base +
		ipahal_get_reg_base() +
		ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n,
		IPA_HW_WDI3_RX_MBOX_START_INDEX/32,
		IPA_HW_WDI3_RX_MBOX_START_INDEX % 32);

	IPADBG("client %d (ep: %d) connected\n", rx_client,
		ipa_ep_idx_rx);

	/* setup tx ep cfg */
	ep_tx->valid = 1;
	ep_tx->client = tx_client;
	result = ipa3_disable_data_path(ipa_ep_idx_tx);
	if (result) {
		IPAERR("disable data path failed res=%d ep=%d.\n", result,
			ipa_ep_idx_tx);
		result = -EFAULT;
		goto fail;
	}

	if (in->is_smmu_enabled == false)
		memcpy(&ep_tx->cfg, &in->u_tx.tx.ipa_ep_cfg,
			sizeof(ep_tx->cfg));
	else
		memcpy(&ep_tx->cfg, &in->u_tx.tx_smmu.ipa_ep_cfg,
			sizeof(ep_tx->cfg));

	if (ipa3_cfg_ep(ipa_ep_idx_tx, &ep_tx->cfg)) {
		IPAERR("fail to setup tx pipe cfg\n");
		result = -EFAULT;
		goto fail;
	}

	if (ipa3_send_wdi3_setup_pipe_cmd(in->is_smmu_enabled,
		&in->u_tx.tx, &in->u_tx.tx_smmu, IPA_WDI3_TX_DIR)) {
		IPAERR("fail to send cmd to uc for tx pipe\n");
		result = -EFAULT;
		goto fail;
	}
	out->tx_uc_db_pa = ipa3_ctx->ipa_wrapper_base +
		ipahal_get_reg_base() +
		ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n,
		IPA_HW_WDI3_TX_MBOX_START_INDEX/32,
		IPA_HW_WDI3_TX_MBOX_START_INDEX % 32);
	IPADBG("client %d (ep: %d) connected\n", tx_client,
		ipa_ep_idx_tx);

fail:
	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
	return result;
}

static int ipa3_send_wdi3_common_ch_cmd(int ipa_ep_idx, int command)
{
	struct ipa_mem_buffer cmd;
	struct IpaHwOffloadCommonChCmdData_t *cmd_data;
	union IpaHwWdi3CommonChCmdData_t *wdi3;
	int result = 0;

	cmd.size = sizeof(*cmd_data);
	cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
		&cmd.phys_base, GFP_KERNEL);
	if (cmd.base == NULL) {
		IPAERR("fail to get DMA memory.\n");
		return -ENOMEM;
	}

	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
	/* enable the TX pipe */
	cmd_data = (struct IpaHwOffloadCommonChCmdData_t *)cmd.base;
	cmd_data->protocol = IPA_HW_FEATURE_WDI3;

	wdi3 = &cmd_data->CommonCh_params.Wdi3CommonCh_params;
	wdi3->params.ipa_pipe_number = ipa_ep_idx;
	result = ipa3_uc_send_cmd((u32)(cmd.phys_base), command,
				IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS,
				false, 10*HZ);
	if (result) {
		result = -EFAULT;
		goto fail;
	}

fail:
	dma_free_coherent(ipa3_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base);
	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
	return result;
}

int ipa3_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
{
	struct ipa3_ep_context *ep_tx, *ep_rx;
	int result = 0;

	IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
	IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);

	if (ipa_ep_idx_tx < 0 || ipa_ep_idx_tx >= IPA3_MAX_NUM_PIPES ||
		ipa_ep_idx_rx < 0 || ipa_ep_idx_rx >= IPA3_MAX_NUM_PIPES) {
		IPAERR("invalid ipa ep index\n");
		return -EINVAL;
	}

	ep_tx = &ipa3_ctx->ep[ipa_ep_idx_tx];
	ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx];

	/* tear down tx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
		IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN)) {
		IPAERR("fail to tear down tx pipe\n");
		result = -EFAULT;
		goto fail;
	}
	ipa3_disable_data_path(ipa_ep_idx_tx);
	memset(ep_tx, 0, sizeof(struct ipa3_ep_context));
	IPADBG("tx client (ep: %d) disconnected\n", ipa_ep_idx_tx);
	IPAERR("wdi3 over uc offload not supported");
	WARN_ON(1);

	/* tear down rx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
		IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN)) {
		IPAERR("fail to tear down rx pipe\n");
		result = -EFAULT;
		goto fail;
	}
	ipa3_disable_data_path(ipa_ep_idx_rx);
	ipa3_delete_dflt_flt_rules(ipa_ep_idx_rx);
	memset(ep_rx, 0, sizeof(struct ipa3_ep_context));
	IPADBG("rx client (ep: %d) disconnected\n", ipa_ep_idx_rx);

fail:
	return result;
	return -EFAULT;
}

int ipa3_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
{
	struct ipa3_ep_context *ep_tx, *ep_rx;
	int result = 0;

	IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
	IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);

	ep_tx = &ipa3_ctx->ep[ipa_ep_idx_tx];
	ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx];

	/* enable tx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
		IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
		IPAERR("fail to enable tx pipe\n");
		result = -EFAULT;
		goto fail;
	}

	/* resume tx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
		IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
		IPAERR("fail to resume tx pipe\n");
		result = -EFAULT;
		goto fail;
	}

	/* enable rx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
		IPA_CPU_2_HW_CMD_OFFLOAD_ENABLE)) {
		IPAERR("fail to enable rx pipe\n");
		result = -EFAULT;
		goto fail;
	}

	/* resume rx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
		IPA_CPU_2_HW_CMD_OFFLOAD_RESUME)) {
		IPAERR("fail to resume rx pipe\n");
		result = -EFAULT;
		goto fail;
	}

	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
	IPAERR("wdi3 over uc offload not supported");
	WARN_ON(1);

	/* enable data path */
	result = ipa3_enable_data_path(ipa_ep_idx_rx);
	if (result) {
		IPAERR("enable data path failed res=%d clnt=%d.\n", result,
			ipa_ep_idx_rx);
		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
	return -EFAULT;
}

	result = ipa3_enable_data_path(ipa_ep_idx_tx);
	if (result) {
		IPAERR("enable data path failed res=%d clnt=%d.\n", result,
			ipa_ep_idx_tx);
		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
		return -EFAULT;
	}

	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();

fail:
	return result;
}

int ipa3_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx)
{
	struct ipa3_ep_context *ep_tx, *ep_rx;
	int result = 0;

	IPADBG("ep_tx = %d\n", ipa_ep_idx_tx);
	IPADBG("ep_rx = %d\n", ipa_ep_idx_rx);

	ep_tx = &ipa3_ctx->ep[ipa_ep_idx_tx];
	ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx];

	/* suspend tx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
		IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND)) {
		IPAERR("fail to suspend tx pipe\n");
		result = -EFAULT;
		goto fail;
	}
	IPAERR("wdi3 over uc offload not supported");
	WARN_ON(1);

	/* disable tx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_tx,
		IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE)) {
		IPAERR("fail to disable tx pipe\n");
		result = -EFAULT;
		goto fail;
	}

	/* suspend rx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
		IPA_CPU_2_HW_CMD_OFFLOAD_SUSPEND)) {
		IPAERR("fail to suspend rx pipe\n");
		result = -EFAULT;
		goto fail;
	}

	/* disable rx pipe */
	if (ipa3_send_wdi3_common_ch_cmd(ipa_ep_idx_rx,
		IPA_CPU_2_HW_CMD_OFFLOAD_DISABLE)) {
		IPAERR("fail to disable rx pipe\n");
		result = -EFAULT;
		goto fail;
	}

fail:
	return result;
	return -EFAULT;
}