mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge "msm: ipa4: add SMMU support for EMAC"
This commit is contained in:
commit
46e1c1ad14
@ -306,6 +306,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_clear_endpoint_delay() - Clear ep_delay.
|
||||
* @clnt_hdl: [in] IPA client handle
|
||||
@ -3071,12 +3111,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;
|
||||
}
|
||||
|
@ -389,7 +389,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);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* 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
|
||||
@ -71,6 +71,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];
|
||||
@ -393,6 +394,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(¶ms->buff_pool_base_sgt);
|
||||
ipa_smmu_free_sgt(¶ms->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)
|
||||
@ -400,6 +446,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) {
|
||||
@ -453,7 +504,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())
|
||||
@ -548,6 +613,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;
|
||||
|
||||
if (ipa_pm_is_used()) {
|
||||
@ -575,12 +645,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;
|
||||
}
|
||||
|
@ -1148,7 +1148,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);
|
||||
@ -1171,7 +1172,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);
|
||||
@ -1183,14 +1185,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;
|
||||
@ -1199,43 +1203,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,
|
||||
@ -1321,18 +1288,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;
|
||||
@ -1437,9 +1403,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))
|
||||
|
@ -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_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-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
|
||||
@ -19,7 +19,9 @@
|
||||
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);
|
||||
|
||||
int ipa_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *user_data),
|
||||
void *user_data);
|
||||
|
@ -506,6 +506,19 @@ struct iommu_domain *ipa3_get_wlan_smmu_domain(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct iommu_domain *ipa3_get_smmu_domain_by_type(enum ipa_smmu_cb_type cb_type)
|
||||
{
|
||||
|
||||
if (cb_type == IPA_SMMU_CB_WLAN && smmu_cb[IPA_SMMU_CB_WLAN].valid)
|
||||
return smmu_cb[IPA_SMMU_CB_WLAN].iommu;
|
||||
|
||||
if (smmu_cb[cb_type].valid)
|
||||
return smmu_cb[cb_type].mapping->domain;
|
||||
|
||||
IPAERR("CB#%d not valid\n", cb_type);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct device *ipa3_get_dma_dev(void)
|
||||
{
|
||||
|
@ -521,15 +521,23 @@ static bool ipa3_is_legal_params(struct ipa_request_gsi_channel_params *params)
|
||||
return true;
|
||||
}
|
||||
|
||||
int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map)
|
||||
int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map,
|
||||
enum ipa_smmu_cb_type cb_type)
|
||||
{
|
||||
struct iommu_domain *smmu_domain;
|
||||
int res;
|
||||
|
||||
if (ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP])
|
||||
return 0;
|
||||
if (cb_type >= IPA_SMMU_CB_MAX) {
|
||||
IPAERR("invalid cb_type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
smmu_domain = ipa3_get_smmu_domain();
|
||||
if (ipa3_ctx->s1_bypass_arr[cb_type]) {
|
||||
IPADBG("CB# %d is set to s1 bypass\n", cb_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
smmu_domain = ipa3_get_smmu_domain_by_type(cb_type);
|
||||
if (!smmu_domain) {
|
||||
IPAERR("invalid smmu domain\n");
|
||||
return -EINVAL;
|
||||
@ -553,7 +561,8 @@ int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt)
|
||||
int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt,
|
||||
enum ipa_smmu_cb_type cb_type)
|
||||
{
|
||||
struct iommu_domain *smmu_domain;
|
||||
int res;
|
||||
@ -565,10 +574,17 @@ int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt)
|
||||
int i;
|
||||
struct page *page;
|
||||
|
||||
if (ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP])
|
||||
return 0;
|
||||
if (cb_type >= IPA_SMMU_CB_MAX) {
|
||||
IPAERR("invalid cb_type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
smmu_domain = ipa3_get_smmu_domain();
|
||||
if (ipa3_ctx->s1_bypass_arr[cb_type]) {
|
||||
IPADBG("CB# %d is set to s1 bypass\n", cb_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
smmu_domain = ipa3_get_smmu_domain_by_type(cb_type);
|
||||
if (!smmu_domain) {
|
||||
IPAERR("invalid smmu domain\n");
|
||||
return -EINVAL;
|
||||
|
@ -118,6 +118,14 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* round addresses for closes page per SMMU requirements */
|
||||
#define IPA_SMMU_ROUND_TO_PAGE(iova, pa, size, iova_p, pa_p, size_p) \
|
||||
do { \
|
||||
(iova_p) = rounddown((iova), PAGE_SIZE); \
|
||||
(pa_p) = rounddown((pa), PAGE_SIZE); \
|
||||
(size_p) = roundup((size) + (pa) - (pa_p), PAGE_SIZE); \
|
||||
} while (0)
|
||||
|
||||
#define WLAN_AMPDU_TX_EP 15
|
||||
#define WLAN_PROD_TX_EP 19
|
||||
#define WLAN1_CONS_RX_EP 14
|
||||
@ -1934,7 +1942,8 @@ int ipa3_broadcast_wdi_quota_reach_ind(uint32_t fid, uint64_t num_bytes);
|
||||
int ipa3_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 ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl);
|
||||
int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl,
|
||||
struct ipa_ntn_conn_in_params *params);
|
||||
int ipa3_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv);
|
||||
void ipa3_ntn_uc_dereg_rdyCB(void);
|
||||
int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in,
|
||||
@ -2312,6 +2321,8 @@ struct ipa_smmu_cb_ctx *ipa3_get_smmu_ctx(enum ipa_smmu_cb_type);
|
||||
struct iommu_domain *ipa3_get_smmu_domain(void);
|
||||
struct iommu_domain *ipa3_get_uc_smmu_domain(void);
|
||||
struct iommu_domain *ipa3_get_wlan_smmu_domain(void);
|
||||
struct iommu_domain *ipa3_get_smmu_domain_by_type
|
||||
(enum ipa_smmu_cb_type cb_type);
|
||||
int ipa3_iommu_map(struct iommu_domain *domain, unsigned long iova,
|
||||
phys_addr_t paddr, size_t size, int prot);
|
||||
int ipa3_ap_suspend(struct device *dev);
|
||||
@ -2346,8 +2357,10 @@ const char *ipa_hw_error_str(enum ipa3_hw_errors err_type);
|
||||
int ipa_gsi_ch20_wa(void);
|
||||
int ipa3_rx_poll(u32 clnt_hdl, int budget);
|
||||
void ipa3_recycle_wan_skb(struct sk_buff *skb);
|
||||
int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map);
|
||||
int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt);
|
||||
int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map,
|
||||
enum ipa_smmu_cb_type cb_type);
|
||||
int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt,
|
||||
enum ipa_smmu_cb_type cb_type);
|
||||
void ipa3_reset_freeze_vote(void);
|
||||
int ipa3_ntn_init(void);
|
||||
int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats);
|
||||
|
@ -221,8 +221,11 @@ static int ipa3_uc_send_ntn_setup_pipe_cmd(
|
||||
|
||||
IPADBG("ring_base_pa = 0x%pa\n",
|
||||
&ntn_info->ring_base_pa);
|
||||
IPADBG("ring_base_iova = 0x%pa\n",
|
||||
&ntn_info->ring_base_iova);
|
||||
IPADBG("ntn_ring_size = %d\n", ntn_info->ntn_ring_size);
|
||||
IPADBG("buff_pool_base_pa = 0x%pa\n", &ntn_info->buff_pool_base_pa);
|
||||
IPADBG("buff_pool_base_iova = 0x%pa\n", &ntn_info->buff_pool_base_iova);
|
||||
IPADBG("num_buffers = %d\n", ntn_info->num_buffers);
|
||||
IPADBG("data_buff_size = %d\n", ntn_info->data_buff_size);
|
||||
IPADBG("tail_ptr_base_pa = 0x%pa\n", &ntn_info->ntn_reg_base_ptr_pa);
|
||||
@ -248,8 +251,15 @@ static int ipa3_uc_send_ntn_setup_pipe_cmd(
|
||||
Ntn_params = &cmd_data->SetupCh_params.NtnSetupCh_params;
|
||||
}
|
||||
|
||||
Ntn_params->ring_base_pa = ntn_info->ring_base_pa;
|
||||
Ntn_params->buff_pool_base_pa = ntn_info->buff_pool_base_pa;
|
||||
if (ntn_info->smmu_enabled) {
|
||||
Ntn_params->ring_base_pa = (u32)ntn_info->ring_base_iova;
|
||||
Ntn_params->buff_pool_base_pa =
|
||||
(u32)ntn_info->buff_pool_base_iova;
|
||||
} else {
|
||||
Ntn_params->ring_base_pa = ntn_info->ring_base_pa;
|
||||
Ntn_params->buff_pool_base_pa = ntn_info->buff_pool_base_pa;
|
||||
}
|
||||
|
||||
Ntn_params->ntn_ring_size = ntn_info->ntn_ring_size;
|
||||
Ntn_params->num_buffers = ntn_info->num_buffers;
|
||||
Ntn_params->ntn_reg_base_ptr_pa = ntn_info->ntn_reg_base_ptr_pa;
|
||||
@ -268,6 +278,128 @@ static int ipa3_uc_send_ntn_setup_pipe_cmd(
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params,
|
||||
bool map)
|
||||
{
|
||||
struct iommu_domain *smmu_domain;
|
||||
int result;
|
||||
int i;
|
||||
u64 iova;
|
||||
phys_addr_t pa;
|
||||
u64 iova_p;
|
||||
phys_addr_t pa_p;
|
||||
u32 size_p;
|
||||
|
||||
if (params->data_buff_size > PAGE_SIZE) {
|
||||
IPAERR("invalid data buff size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
result = ipa3_smmu_map_peer_reg(rounddown(params->ntn_reg_base_ptr_pa,
|
||||
PAGE_SIZE), map, IPA_SMMU_CB_UC);
|
||||
if (result) {
|
||||
IPAERR("failed to %s uC regs %d\n",
|
||||
map ? "map" : "unmap", result);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (params->smmu_enabled) {
|
||||
IPADBG("smmu is enabled on EMAC\n");
|
||||
result = ipa3_smmu_map_peer_buff((u64)params->ring_base_iova,
|
||||
params->ntn_ring_size, map, params->ring_base_sgt,
|
||||
IPA_SMMU_CB_UC);
|
||||
if (result) {
|
||||
IPAERR("failed to %s ntn ring %d\n",
|
||||
map ? "map" : "unmap", result);
|
||||
goto fail_map_ring;
|
||||
}
|
||||
result = ipa3_smmu_map_peer_buff(
|
||||
(u64)params->buff_pool_base_iova,
|
||||
params->num_buffers * 4, map,
|
||||
params->buff_pool_base_sgt, IPA_SMMU_CB_UC);
|
||||
if (result) {
|
||||
IPAERR("failed to %s pool buffs %d\n",
|
||||
map ? "map" : "unmap", result);
|
||||
goto fail_map_buffer_smmu_enabled;
|
||||
}
|
||||
} else {
|
||||
IPADBG("smmu is disabled on EMAC\n");
|
||||
result = ipa3_smmu_map_peer_buff((u64)params->ring_base_pa,
|
||||
params->ntn_ring_size, map, NULL, IPA_SMMU_CB_UC);
|
||||
if (result) {
|
||||
IPAERR("failed to %s ntn ring %d\n",
|
||||
map ? "map" : "unmap", result);
|
||||
goto fail_map_ring;
|
||||
}
|
||||
result = ipa3_smmu_map_peer_buff(params->buff_pool_base_pa,
|
||||
params->num_buffers * 4, map, NULL, IPA_SMMU_CB_UC);
|
||||
if (result) {
|
||||
IPAERR("failed to %s pool buffs %d\n",
|
||||
map ? "map" : "unmap", result);
|
||||
goto fail_map_buffer_smmu_disabled;
|
||||
}
|
||||
}
|
||||
|
||||
if (ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) {
|
||||
IPADBG("AP SMMU is set to s1 bypass\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
smmu_domain = ipa3_get_smmu_domain();
|
||||
if (!smmu_domain) {
|
||||
IPAERR("invalid smmu domain\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < params->num_buffers; i++) {
|
||||
iova = (u64)params->data_buff_list[i].iova;
|
||||
pa = (phys_addr_t)params->data_buff_list[i].pa;
|
||||
IPA_SMMU_ROUND_TO_PAGE(iova, pa, params->data_buff_size, iova_p,
|
||||
pa_p, size_p);
|
||||
IPADBG("%s 0x%llx to 0x%pa size %d\n", map ? "mapping" :
|
||||
"unmapping", iova_p, &pa_p, size_p);
|
||||
if (map) {
|
||||
result = ipa3_iommu_map(smmu_domain, iova_p, pa_p,
|
||||
size_p, IOMMU_READ | IOMMU_WRITE);
|
||||
if (result)
|
||||
IPAERR("Fail to map 0x%llx\n", iova);
|
||||
} else {
|
||||
result = iommu_unmap(smmu_domain, iova_p, size_p);
|
||||
if (result != params->data_buff_size)
|
||||
IPAERR("Fail to unmap 0x%llx\n", iova);
|
||||
}
|
||||
if (result) {
|
||||
if (params->smmu_enabled)
|
||||
goto fail_map_data_buff_smmu_enabled;
|
||||
else
|
||||
goto fail_map_data_buff_smmu_disabled;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail_map_data_buff_smmu_enabled:
|
||||
ipa3_smmu_map_peer_buff((u64)params->buff_pool_base_iova,
|
||||
params->num_buffers * 4, !map, NULL, IPA_SMMU_CB_UC);
|
||||
goto fail_map_buffer_smmu_enabled;
|
||||
fail_map_data_buff_smmu_disabled:
|
||||
ipa3_smmu_map_peer_buff(params->buff_pool_base_pa,
|
||||
params->num_buffers * 4, !map, NULL, IPA_SMMU_CB_UC);
|
||||
goto fail_map_buffer_smmu_disabled;
|
||||
fail_map_buffer_smmu_enabled:
|
||||
ipa3_smmu_map_peer_buff((u64)params->ring_base_iova,
|
||||
params->ntn_ring_size, !map, params->ring_base_sgt,
|
||||
IPA_SMMU_CB_UC);
|
||||
goto fail_map_ring;
|
||||
fail_map_buffer_smmu_disabled:
|
||||
ipa3_smmu_map_peer_buff((u64)params->ring_base_pa,
|
||||
params->ntn_ring_size, !map, NULL, IPA_SMMU_CB_UC);
|
||||
fail_map_ring:
|
||||
ipa3_smmu_map_peer_reg(rounddown(params->ntn_reg_base_ptr_pa,
|
||||
PAGE_SIZE), !map, IPA_SMMU_CB_UC);
|
||||
fail:
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipa3_setup_uc_ntn_pipes() - setup uc offload pipes
|
||||
*/
|
||||
@ -324,10 +456,16 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = ipa3_smmu_map_uc_ntn_pipes(&in->ul, true);
|
||||
if (result) {
|
||||
IPAERR("failed to map SMMU for UL %d\n", result);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ipa3_uc_send_ntn_setup_pipe_cmd(&in->ul, IPA_NTN_RX_DIR)) {
|
||||
IPAERR("fail to send cmd to uc for ul pipe\n");
|
||||
result = -EFAULT;
|
||||
goto fail;
|
||||
goto fail_smmu_map_ul;
|
||||
}
|
||||
ipa3_install_dflt_flt_rules(ipa_ep_idx_ul);
|
||||
outp->ul_uc_db_pa = IPA_UC_NTN_DB_PA_RX;
|
||||
@ -346,13 +484,19 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in,
|
||||
if (ipa3_cfg_ep(ipa_ep_idx_dl, &ep_dl->cfg)) {
|
||||
IPAERR("fail to setup dl pipe cfg\n");
|
||||
result = -EFAULT;
|
||||
goto fail;
|
||||
goto fail_smmu_map_ul;
|
||||
}
|
||||
|
||||
result = ipa3_smmu_map_uc_ntn_pipes(&in->dl, true);
|
||||
if (result) {
|
||||
IPAERR("failed to map SMMU for DL %d\n", result);
|
||||
goto fail_smmu_map_ul;
|
||||
}
|
||||
|
||||
if (ipa3_uc_send_ntn_setup_pipe_cmd(&in->dl, IPA_NTN_TX_DIR)) {
|
||||
IPAERR("fail to send cmd to uc for dl pipe\n");
|
||||
result = -EFAULT;
|
||||
goto fail;
|
||||
goto fail_smmu_map_dl;
|
||||
}
|
||||
outp->dl_uc_db_pa = IPA_UC_NTN_DB_PA_TX;
|
||||
ep_dl->uc_offload_state |= IPA_UC_OFFLOAD_CONNECTED;
|
||||
@ -362,11 +506,17 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in,
|
||||
IPAERR("Enable data path failed res=%d clnt=%d.\n", result,
|
||||
ipa_ep_idx_dl);
|
||||
result = -EFAULT;
|
||||
goto fail;
|
||||
goto fail_smmu_map_dl;
|
||||
}
|
||||
IPADBG("client %d (ep: %d) connected\n", in->dl.client,
|
||||
ipa_ep_idx_dl);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_smmu_map_dl:
|
||||
ipa3_smmu_map_uc_ntn_pipes(&in->dl, false);
|
||||
fail_smmu_map_ul:
|
||||
ipa3_smmu_map_uc_ntn_pipes(&in->ul, false);
|
||||
fail:
|
||||
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
|
||||
return result;
|
||||
@ -377,7 +527,7 @@ fail:
|
||||
*/
|
||||
|
||||
int ipa3_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 ipa_mem_buffer cmd;
|
||||
struct ipa3_ep_context *ep_ul, *ep_dl;
|
||||
@ -442,6 +592,13 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* unmap the DL pipe */
|
||||
result = ipa3_smmu_map_uc_ntn_pipes(¶ms->dl, false);
|
||||
if (result) {
|
||||
IPAERR("failed to unmap SMMU for DL %d\n", result);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* teardown the UL pipe */
|
||||
tear->params.ipa_pipe_number = ipa_ep_idx_ul;
|
||||
result = ipa3_uc_send_cmd((u32)(cmd.phys_base),
|
||||
@ -453,6 +610,14 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul,
|
||||
result = -EFAULT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* unmap the UL pipe */
|
||||
result = ipa3_smmu_map_uc_ntn_pipes(¶ms->ul, false);
|
||||
if (result) {
|
||||
IPAERR("failed to unmap SMMU for UL %d\n", result);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ipa3_delete_dflt_flt_rules(ipa_ep_idx_ul);
|
||||
memset(&ipa3_ctx->ep[ipa_ep_idx_ul], 0, sizeof(struct ipa3_ep_context));
|
||||
IPADBG("ul client (ep: %d) disconnected\n", ipa_ep_idx_ul);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* 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
|
||||
@ -69,13 +69,29 @@ struct ipa_uc_offload_intf_params {
|
||||
enum ipa_client_type alt_dst_pipe;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ntn_buff_smmu_map - IPA iova->pa SMMU mapping
|
||||
* @iova: virtual address of the data buffer
|
||||
* @pa: physical address of the data buffer
|
||||
*/
|
||||
struct ntn_buff_smmu_map {
|
||||
dma_addr_t iova;
|
||||
phys_addr_t pa;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ipa_ntn_setup_info - NTN TX/Rx configuration
|
||||
* @client: type of "client" (IPA_CLIENT_ODU#_PROD/CONS)
|
||||
* @smmu_enabled: SMMU is enabled for uC or not
|
||||
* @ring_base_pa: physical address of the base of the Tx/Rx ring
|
||||
* @ring_base_iova: virtual address of the base of the Tx/Rx ring
|
||||
* @ring_base_sgt:Scatter table for ntn_rings,contains valid non NULL
|
||||
* value when ENAC S1-SMMU enabed, else NULL.
|
||||
* @ntn_ring_size: size of the Tx/Rx ring (in terms of elements)
|
||||
* @buff_pool_base_pa: physical address of the base of the Tx/Rx
|
||||
* buffer pool
|
||||
* @buff_pool_base_pa: physical address of the base of the Tx/Rx buffer pool
|
||||
* @buff_pool_base_iova: virtual address of the base of the Tx/Rx buffer pool
|
||||
* @buff_pool_base_sgt: Scatter table for buffer pools,contains valid non NULL
|
||||
* value when EMAC S1-SMMU enabed, else NULL.
|
||||
* @num_buffers: Rx/Tx buffer pool size (in terms of elements)
|
||||
* @data_buff_size: size of the each data buffer allocated in DDR
|
||||
* @ntn_reg_base_ptr_pa: physical address of the Tx/Rx NTN Ring's
|
||||
@ -83,11 +99,21 @@ struct ipa_uc_offload_intf_params {
|
||||
*/
|
||||
struct ipa_ntn_setup_info {
|
||||
enum ipa_client_type client;
|
||||
bool smmu_enabled;
|
||||
phys_addr_t ring_base_pa;
|
||||
dma_addr_t ring_base_iova;
|
||||
struct sg_table *ring_base_sgt;
|
||||
|
||||
u32 ntn_ring_size;
|
||||
|
||||
phys_addr_t buff_pool_base_pa;
|
||||
dma_addr_t buff_pool_base_iova;
|
||||
struct sg_table *buff_pool_base_sgt;
|
||||
|
||||
struct ntn_buff_smmu_map *data_buff_list;
|
||||
|
||||
u32 num_buffers;
|
||||
|
||||
u32 data_buff_size;
|
||||
|
||||
phys_addr_t ntn_reg_base_ptr_pa;
|
||||
|
Loading…
x
Reference in New Issue
Block a user