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

Commit e46e77c5 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa4: add SMMU support for EMAC"

parents 47401c1e b1bafa41
Loading
Loading
Loading
Loading
+42 −2
Original line number Diff line number Diff line
@@ -294,6 +294,46 @@ u8 *ipa_pad_to_32(u8 *dest)
	return dest;
}

int ipa_smmu_store_sgt(struct sg_table **out_ch_ptr,
	struct sg_table *in_sgt_ptr)
{
	unsigned int nents;

	if (in_sgt_ptr != NULL) {
		*out_ch_ptr = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
		if (*out_ch_ptr == NULL)
			return -ENOMEM;

		nents = in_sgt_ptr->nents;

		(*out_ch_ptr)->sgl =
			kcalloc(nents, sizeof(struct scatterlist),
				GFP_KERNEL);
		if ((*out_ch_ptr)->sgl == NULL) {
			kfree(*out_ch_ptr);
			*out_ch_ptr = NULL;
			return -ENOMEM;
		}

		memcpy((*out_ch_ptr)->sgl, in_sgt_ptr->sgl,
			nents*sizeof((*out_ch_ptr)->sgl));
		(*out_ch_ptr)->nents = nents;
		(*out_ch_ptr)->orig_nents = in_sgt_ptr->orig_nents;
	}
	return 0;
}

int ipa_smmu_free_sgt(struct sg_table **out_sgt_ptr)
{
	if (*out_sgt_ptr != NULL) {
		kfree((*out_sgt_ptr)->sgl);
		(*out_sgt_ptr)->sgl = NULL;
		kfree(*out_sgt_ptr);
		*out_sgt_ptr = NULL;
	}
	return 0;
}

/**
 * ipa_connect() - low-level IPA client connect
 * @in:	[in] input parameters from client
@@ -3111,12 +3151,12 @@ int ipa_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *inp,
 * ipa_tear_down_uc_offload_pipes() - tear down uc offload pipes
 */
int ipa_tear_down_uc_offload_pipes(int ipa_ep_idx_ul,
		int ipa_ep_idx_dl)
		int ipa_ep_idx_dl, struct ipa_ntn_conn_in_params *params)
{
	int ret;

	IPA_API_DISPATCH_RETURN(ipa_tear_down_uc_offload_pipes, ipa_ep_idx_ul,
		ipa_ep_idx_dl);
		ipa_ep_idx_dl, params);

	return ret;
}
+1 −1
Original line number Diff line number Diff line
@@ -394,7 +394,7 @@ struct ipa_api_controller {
		struct ipa_ntn_conn_out_params *);

	int (*ipa_tear_down_uc_offload_pipes)(int ipa_ep_idx_ul,
		int ipa_ep_idx_dl);
		int ipa_ep_idx_dl, struct ipa_ntn_conn_in_params *params);

	struct device *(*ipa_get_pdev)(void);

+77 −3
Original line number Diff line number Diff line
/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -73,6 +73,7 @@ struct ipa_uc_offload_ctx {
	ipa_notify_cb notify;
	struct completion ntn_completion;
	u32 pm_hdl;
	struct ipa_ntn_conn_in_params conn;
};

static struct ipa_uc_offload_ctx *ipa_uc_offload_ctx[IPA_UC_MAX_PROT_SIZE];
@@ -403,6 +404,51 @@ static void ipa_uc_offload_rm_notify(void *user_data, enum ipa_rm_event event,
	}
}

static int ipa_uc_ntn_alloc_conn_smmu_info(struct ipa_ntn_setup_info *dest,
	struct ipa_ntn_setup_info *source)
{
	int result;

	IPA_UC_OFFLOAD_DBG("Allocating smmu info\n");

	memcpy(dest, source, sizeof(struct ipa_ntn_setup_info));

	dest->data_buff_list =
		kcalloc(dest->num_buffers, sizeof(struct ntn_buff_smmu_map),
			GFP_KERNEL);
	if (dest->data_buff_list == NULL) {
		IPA_UC_OFFLOAD_ERR("failed to alloc smmu info\n");
		return -ENOMEM;
	}

	memcpy(dest->data_buff_list, source->data_buff_list,
		sizeof(struct ntn_buff_smmu_map) * dest->num_buffers);

	result = ipa_smmu_store_sgt(&dest->buff_pool_base_sgt,
		source->buff_pool_base_sgt);
	if (result) {
		kfree(dest->data_buff_list);
		return result;
	}

	result = ipa_smmu_store_sgt(&dest->ring_base_sgt,
		source->ring_base_sgt);
	if (result) {
		kfree(dest->data_buff_list);
		ipa_smmu_free_sgt(&dest->buff_pool_base_sgt);
		return result;
	}

	return 0;
}

static void ipa_uc_ntn_free_conn_smmu_info(struct ipa_ntn_setup_info *params)
{
	kfree(params->data_buff_list);
	ipa_smmu_free_sgt(&params->buff_pool_base_sgt);
	ipa_smmu_free_sgt(&params->ring_base_sgt);
}

int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp,
			struct ipa_ntn_conn_out_params *outp,
			struct ipa_uc_offload_ctx *ntn_ctx)
@@ -410,6 +456,11 @@ int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp,
	int result = 0;
	enum ipa_uc_offload_state prev_state;

	if (ntn_ctx->conn.dl.smmu_enabled != ntn_ctx->conn.ul.smmu_enabled) {
		IPA_UC_OFFLOAD_ERR("ul and dl smmu enablement do not match\n");
		return -EINVAL;
	}

	prev_state = ntn_ctx->state;
	if (inp->dl.ring_base_pa % IPA_NTN_DMA_POOL_ALIGNMENT ||
		inp->dl.buff_pool_base_pa % IPA_NTN_DMA_POOL_ALIGNMENT) {
@@ -467,7 +518,21 @@ int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp,
		goto fail;
	}

	return 0;
	if (ntn_ctx->conn.dl.smmu_enabled) {
		result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.dl,
			&inp->dl);
		if (result) {
			IPA_UC_OFFLOAD_ERR("alloc failure on TX\n");
			goto fail;
		}
		result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.ul,
			&inp->ul);
		if (result) {
			ipa_uc_ntn_free_conn_smmu_info(&ntn_ctx->conn.dl);
			IPA_UC_OFFLOAD_ERR("alloc failure on RX\n");
			goto fail;
		}
	}

fail:
	if (!ipa_pm_is_used())
@@ -563,6 +628,11 @@ static int ipa_uc_ntn_disconn_pipes(struct ipa_uc_offload_ctx *ntn_ctx)
	int ipa_ep_idx_ul, ipa_ep_idx_dl;
	int ret = 0;

	if (ntn_ctx->conn.dl.smmu_enabled != ntn_ctx->conn.ul.smmu_enabled) {
		IPA_UC_OFFLOAD_ERR("ul and dl smmu enablement do not match\n");
		return -EINVAL;
	}

	ntn_ctx->state = IPA_UC_OFFLOAD_STATE_INITIALIZED;

#ifdef CONFIG_IPA3
@@ -594,12 +664,16 @@ static int ipa_uc_ntn_disconn_pipes(struct ipa_uc_offload_ctx *ntn_ctx)

	ipa_ep_idx_ul = ipa_get_ep_mapping(IPA_CLIENT_ETHERNET_PROD);
	ipa_ep_idx_dl = ipa_get_ep_mapping(IPA_CLIENT_ETHERNET_CONS);
	ret = ipa_tear_down_uc_offload_pipes(ipa_ep_idx_ul, ipa_ep_idx_dl);
	ret = ipa_tear_down_uc_offload_pipes(ipa_ep_idx_ul, ipa_ep_idx_dl,
		&ntn_ctx->conn);
	if (ret) {
		IPA_UC_OFFLOAD_ERR("fail to tear down ntn offload pipes, %d\n",
						 ret);
		return -EFAULT;
	}
	if (ntn_ctx->conn.dl.smmu_enabled)
		ipa_uc_ntn_free_conn_smmu_info(&ntn_ctx->conn.dl);
		ipa_uc_ntn_free_conn_smmu_info(&ntn_ctx->conn.ul);

	return ret;
}
+15 −49
Original line number Diff line number Diff line
@@ -1149,7 +1149,8 @@ static int ipa3_usb_smmu_map_xdci_channel(
		if (ipa3_usb_ctx->smmu_reg_map.cnt == 0) {
			ipa3_usb_ctx->smmu_reg_map.addr = gevntcount_r;
			result = ipa3_smmu_map_peer_reg(
				ipa3_usb_ctx->smmu_reg_map.addr, true);
				ipa3_usb_ctx->smmu_reg_map.addr, true,
				IPA_SMMU_CB_AP);
			if (result) {
				IPA_USB_ERR("failed to map USB regs %d\n",
					result);
@@ -1172,7 +1173,8 @@ static int ipa3_usb_smmu_map_xdci_channel(

		if (ipa3_usb_ctx->smmu_reg_map.cnt == 1) {
			result = ipa3_smmu_map_peer_reg(
				ipa3_usb_ctx->smmu_reg_map.addr, false);
				ipa3_usb_ctx->smmu_reg_map.addr, false,
				IPA_SMMU_CB_AP);
			if (result) {
				IPA_USB_ERR("failed to unmap USB regs %d\n",
					result);
@@ -1184,14 +1186,16 @@ static int ipa3_usb_smmu_map_xdci_channel(


	result = ipa3_smmu_map_peer_buff(params->xfer_ring_base_addr_iova,
		params->xfer_ring_len, map, params->sgt_xfer_rings);
		params->xfer_ring_len, map, params->sgt_xfer_rings,
		IPA_SMMU_CB_AP);
	if (result) {
		IPA_USB_ERR("failed to map Xfer ring %d\n", result);
		return result;
	}

	result = ipa3_smmu_map_peer_buff(params->data_buff_base_addr_iova,
		params->data_buff_base_len, map, params->sgt_data_buff);
		params->data_buff_base_len, map, params->sgt_data_buff,
		IPA_SMMU_CB_AP);
	if (result) {
		IPA_USB_ERR("failed to map TRBs buff %d\n", result);
		return result;
@@ -1200,43 +1204,6 @@ static int ipa3_usb_smmu_map_xdci_channel(
	return 0;
}

static int ipa3_usb_smmu_store_sgt(struct sg_table **out_ch_ptr,
	struct sg_table *in_sgt_ptr)
{
	unsigned int nents;

	if (in_sgt_ptr != NULL) {
		*out_ch_ptr = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
		if (*out_ch_ptr == NULL)
			return -ENOMEM;

		nents = in_sgt_ptr->nents;

		(*out_ch_ptr)->sgl =
			kcalloc(nents, sizeof(struct scatterlist),
				GFP_KERNEL);
		if ((*out_ch_ptr)->sgl == NULL)
			return -ENOMEM;

		memcpy((*out_ch_ptr)->sgl, in_sgt_ptr->sgl,
			nents*sizeof((*out_ch_ptr)->sgl));
		(*out_ch_ptr)->nents = nents;
		(*out_ch_ptr)->orig_nents = in_sgt_ptr->orig_nents;
	}
	return 0;
}

static int ipa3_usb_smmu_free_sgt(struct sg_table **out_sgt_ptr)
{
	if (*out_sgt_ptr != NULL) {
		kfree((*out_sgt_ptr)->sgl);
		(*out_sgt_ptr)->sgl = NULL;
		kfree(*out_sgt_ptr);
		*out_sgt_ptr = NULL;
	}
	return 0;
}

static int ipa3_usb_request_xdci_channel(
	struct ipa_usb_xdci_chan_params *params,
	enum ipa_usb_direction dir,
@@ -1327,18 +1294,17 @@ static int ipa3_usb_request_xdci_channel(
		xdci_ch_params = &ipa3_usb_ctx->ttype_ctx[ttype].dl_ch_params;

	*xdci_ch_params = *params;
	result = ipa3_usb_smmu_store_sgt(
	result = ipa_smmu_store_sgt(
		&xdci_ch_params->sgt_xfer_rings,
		params->sgt_xfer_rings);
	if (result) {
		ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_xfer_rings);
	if (result)
		return result;
	}
	result = ipa3_usb_smmu_store_sgt(

	result = ipa_smmu_store_sgt(
		&xdci_ch_params->sgt_data_buff,
		params->sgt_data_buff);
	if (result) {
		ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_data_buff);
		ipa_smmu_free_sgt(&xdci_ch_params->sgt_xfer_rings);
		return result;
	}
	chan_params.keep_ipa_awake = params->keep_ipa_awake;
@@ -1443,9 +1409,9 @@ static int ipa3_usb_release_xdci_channel(u32 clnt_hdl,
	result = ipa3_usb_smmu_map_xdci_channel(xdci_ch_params, false);

	if (xdci_ch_params->sgt_xfer_rings != NULL)
		ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_xfer_rings);
		ipa_smmu_free_sgt(&xdci_ch_params->sgt_xfer_rings);
	if (xdci_ch_params->sgt_data_buff != NULL)
		ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_data_buff);
		ipa_smmu_free_sgt(&xdci_ch_params->sgt_data_buff);

	/* Change ipa_usb state to INITIALIZED */
	if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype))
+6 −1
Original line number Diff line number Diff line
@@ -408,7 +408,8 @@ int ipa_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in,
	ipa_notify_cb notify, void *priv, u8 hdr_len,
	struct ipa_ntn_conn_out_params *outp);

int ipa_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl);
int ipa_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl,
	struct ipa_ntn_conn_in_params *params);
u8 *ipa_write_64(u64 w, u8 *dest);
u8 *ipa_write_32(u32 w, u8 *dest);
u8 *ipa_write_16(u16 hw, u8 *dest);
@@ -434,4 +435,8 @@ int ipa_start_gsi_channel(u32 clnt_hdl);

bool ipa_pm_is_used(void);

int ipa_smmu_store_sgt(struct sg_table **out_ch_ptr,
		struct sg_table *in_sgt_ptr);
int ipa_smmu_free_sgt(struct sg_table **out_sgt_ptr);

#endif /* _IPA_COMMON_I_H_ */
Loading