Merge "ipa: Remove is_hdr_proc_ctx flag"
diff --git a/drivers/platform/msm/ipa/ipa_test_module/ipa_test_module_impl.c b/drivers/platform/msm/ipa/ipa_test_module/ipa_test_module_impl.c
index d058711..f100bcf 100644
--- a/drivers/platform/msm/ipa/ipa_test_module/ipa_test_module_impl.c
+++ b/drivers/platform/msm/ipa/ipa_test_module/ipa_test_module_impl.c
@@ -4716,6 +4716,7 @@
break;
case IPA_TEST_IOC_IS_TEST_PROD_FLT_IN_SRAM:
retval = ipa_is_test_prod_flt_in_sram_internal(arg);
+ break;
case IPA_TEST_IOC_GET_MEM_PART:
retval = ipa_test_get_mem_part(arg);
break;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index c35d67c..1ca2f98 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -49,7 +49,7 @@
#endif
#define DRV_NAME "ipa"
-
+#define DELAY_BEFORE_FW_LOAD 500
#define IPA_SUBSYSTEM_NAME "ipa_fws"
#define IPA_UC_SUBSYSTEM_NAME "ipa_uc"
@@ -134,6 +134,7 @@
static void ipa3_load_ipa_fw(struct work_struct *work);
static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw);
+static DECLARE_DELAYED_WORK(ipa3_fw_load_failure_handle, ipa3_load_ipa_fw);
static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work);
static DECLARE_DELAYED_WORK(ipa_dec_clients_disable_clks_on_wq_work,
@@ -2341,16 +2342,7 @@
return 0;
}
-static void ipa3_mac_flt_list_free_cb(void *buff, u32 len, u32 type)
-{
- if (!buff) {
- IPAERR("Null buffer\n");
- return;
- }
- kfree(buff);
-}
-
-static void ipa3_pkt_threshold_free_cb(void *buff, u32 len, u32 type)
+static void ipa3_general_free_cb(void *buff, u32 len, u32 type)
{
if (!buff) {
IPAERR("Null buffer\n");
@@ -2384,7 +2376,7 @@
((struct ipa_ioc_mac_client_list_type *)buff)->flt_state);
retval = ipa3_send_msg(&msg_meta, buff,
- ipa3_mac_flt_list_free_cb);
+ ipa3_general_free_cb);
if (retval) {
IPAERR("ipa3_send_msg failed: %d, msg_type %d\n",
retval,
@@ -2448,7 +2440,7 @@
((struct ipa_set_pkt_threshold *)buff2)->pkt_threshold);
retval = ipa3_send_msg(&msg_meta, buff2,
- ipa3_pkt_threshold_free_cb);
+ ipa3_general_free_cb);
if (retval) {
IPAERR("ipa3_send_msg failed: %d, msg_type %d\n",
retval,
@@ -2512,7 +2504,7 @@
((struct ipa_sw_flt_list_type *)buff)->iface_enable);
retval = ipa3_send_msg(&msg_meta, buff,
- ipa3_mac_flt_list_free_cb);
+ ipa3_general_free_cb);
if (retval) {
IPAERR("ipa3_send_msg failed: %d, msg_type %d\n",
retval,
@@ -2571,7 +2563,7 @@
((struct ipa_ippt_sw_flt_list_type *)buff)->port_enable);
retval = ipa3_send_msg(&msg_meta, buff,
- ipa3_mac_flt_list_free_cb);
+ ipa3_general_free_cb);
if (retval) {
IPAERR("ipa3_send_msg failed: %d, msg_type %d\n",
retval,
@@ -2582,6 +2574,46 @@
return 0;
}
+/**
+ * ipa3_send_macsec_info() - Pass macsec mapping to the IPACM
+ * @event_type: Type of the event - UP or DOWN
+ * @map: pointer to macsec to eth mapping structure
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa3_send_macsec_info(enum ipa_macsec_event event_type, struct ipa_macsec_map *map)
+{
+ struct ipa_msg_meta msg_meta;
+ int res = 0;
+
+ if (!map) {
+ IPAERR("Bad arg: info is NULL\n");
+ res = -EIO;
+ goto done;
+ }
+
+ /*
+ * Prep and send msg to ipacm
+ */
+ memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
+ msg_meta.msg_type = event_type;
+ msg_meta.msg_len = sizeof(struct ipa_macsec_map);
+
+ /*
+ * Post event to ipacm
+ */
+ res = ipa3_send_msg(&msg_meta, map, ipa3_general_free_cb);
+
+ if (res) {
+ IPAERR_RL("ipa3_send_msg failed: %d\n", res);
+ kfree(map);
+ goto done;
+ }
+
+done:
+ return res;
+}
+
static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int retval = 0;
@@ -2600,6 +2632,8 @@
struct ipa_ioc_get_vlan_mode vlan_mode;
struct ipa_ioc_wigig_fst_switch fst_switch;
struct ipa_ioc_eogre_info eogre_info;
+ struct ipa_ioc_macsec_info macsec_info;
+ struct ipa_macsec_map *macsec_map;
bool send2uC, send2ipacm;
size_t sz;
int pre_entry;
@@ -3982,6 +4016,47 @@
IPAERR("ipa_flt_sram_set_client_prio_high failed! retval=%d\n", retval);
break;
#endif
+
+ case IPA_IOC_ADD_MACSEC_MAPPING:
+ case IPA_IOC_DEL_MACSEC_MAPPING:
+ IPADBG("Got %s\n", cmd == IPA_IOC_ADD_MACSEC_MAPPING ?
+ "IPA_IOC_ADD_MACSEC_MAPPING" : "IPA_IOC_DEL_MACSEC_MAPPING");
+ if (copy_from_user(&macsec_info, (const void __user *) arg,
+ sizeof(struct ipa_ioc_macsec_info))) {
+ IPAERR_RL("copy_from_user for ipa_ioc_macsec_info fails\n");
+ retval = -EFAULT;
+ break;
+ }
+
+ /* Validate the input */
+ if (macsec_info.ioctl_data_size != sizeof(struct ipa_macsec_map)) {
+ IPAERR_RL("data size missmatch\n");
+ retval = -EFAULT;
+ break;
+ }
+
+ macsec_map = kzalloc(sizeof(struct ipa_macsec_map), GFP_KERNEL);
+ if (!macsec_map) {
+ IPAERR("macsec_map memory allocation failed !\n");
+ retval = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(macsec_map, (const void __user *)(macsec_info.ioctl_ptr),
+ sizeof(struct ipa_macsec_map))) {
+ IPAERR_RL("copy_from_user for ipa_macsec_map fails\n");
+ retval = -EFAULT;
+ kfree(macsec_map);
+ break;
+ }
+
+ /* Send message to the IPACM */
+ ipa3_send_macsec_info(
+ (cmd == IPA_IOC_ADD_MACSEC_MAPPING) ?
+ IPA_MACSEC_ADD_EVENT : IPA_MACSEC_DEL_EVENT,
+ macsec_map);
+ break;
+
default:
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return -ENOTTY;
@@ -7909,11 +7984,14 @@
IPADBG("Entry\n");
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
-
+
result = ipa3_attach_to_smmu();
if (result) {
IPAERR("IPA attach to smmu failed %d\n", result);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+ queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
+ &ipa3_fw_load_failure_handle,
+ msecs_to_jiffies(DELAY_BEFORE_FW_LOAD));
return;
}
@@ -7941,13 +8019,18 @@
result = ipa3_manual_load_ipa_fws();
}
- IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
if (result) {
- IPAERR("IPA FW loading process has failed result=%d\n",
- result);
+
+ ipa3_ctx->ipa_pil_load++;
+ IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+ IPADBG("IPA firmware loading deffered to a work queue\n");
+ queue_delayed_work(ipa3_ctx->transport_power_mgmt_wq,
+ &ipa3_fw_load_failure_handle,
+ msecs_to_jiffies(DELAY_BEFORE_FW_LOAD));
return;
}
+ IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
mutex_lock(&ipa3_ctx->fw_load_data.lock);
ipa3_ctx->fw_load_data.state = IPA_FW_LOAD_STATE_LOADED;
mutex_unlock(&ipa3_ctx->fw_load_data.lock);
@@ -8016,7 +8099,7 @@
if (ipa3_ctx->fw_load_data.state == IPA_FW_LOAD_STATE_INIT) {
ipa3_ctx->fw_load_data.state =
IPA_FW_LOAD_STATE_SMMU_DONE;
- goto out;
+ goto sched_fw_load;
}
if (ipa3_ctx->fw_load_data.state ==
IPA_FW_LOAD_STATE_FWFILE_READY) {
@@ -10246,6 +10329,7 @@
}
}
+ cb->done = true;
return 0;
}
@@ -10325,10 +10409,35 @@
ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] = (bypass != 0);
ipa3_ctx->uc_pdev = dev;
-
+ cb->done = true;
return 0;
}
+static void ipa3_ap_iommu_unmap(struct ipa_smmu_cb_ctx *cb, const u32 *add_map, u32 add_map_size) {
+
+ int i, res;
+
+ /* iterate of each entry of the additional mapping array */
+ for (i = 0; i < add_map_size / sizeof(u32); i += 3) {
+ u32 iova = be32_to_cpu(add_map[i]);
+ u32 pa = be32_to_cpu(add_map[i + 1]);
+ u32 size = be32_to_cpu(add_map[i + 2]);
+ unsigned long iova_p;
+ phys_addr_t pa_p;
+ u32 size_p;
+
+ IPA_SMMU_ROUND_TO_PAGE(iova, pa, size,
+ iova_p, pa_p, size_p);
+ IPADBG_LOW("unmapping 0x%lx to 0x%pa size %d\n",
+ iova_p, &pa_p, size_p);
+
+ res = iommu_unmap(cb->iommu_domain,iova_p, size_p);
+ if(res != size_p) {
+ pr_err("iommu unmap failed for AP cb\n");
+ ipa_assert();
+ }
+ }
+}
static int ipa_smmu_ap_cb_probe(struct device *dev)
{
struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
@@ -10463,6 +10572,8 @@
if (ret < 0 && ret != -EEXIST) {
IPAERR("unable to allocate smem MODEM entry\n");
cb->valid = false;
+ if(add_map)
+ ipa3_ap_iommu_unmap(cb, add_map, add_map_size);
return -EFAULT;
}
smem_addr = qcom_smem_get(SMEM_MODEM,
@@ -10471,6 +10582,8 @@
if (IS_ERR(smem_addr)) {
IPAERR("unable to acquire smem MODEM entry\n");
cb->valid = false;
+ if(add_map)
+ ipa3_ap_iommu_unmap(cb, add_map, add_map_size);
return -EFAULT;
}
if (smem_size != ipa_smem_size)
@@ -10491,6 +10604,7 @@
smmu_info.present[IPA_SMMU_CB_AP] = true;
+ cb->done = true;
ipa3_ctx->pdev = dev;
cb->next_addr = cb->va_end;
@@ -10543,14 +10657,21 @@
IPADBG("11AD using shared CB\n");
cb->shared = true;
}
-
+ cb->done = true;
return 0;
}
static int ipa_smmu_cb_probe(struct device *dev, enum ipa_smmu_cb_type cb_type)
{
+ struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(cb_type);
+
+ if((cb != NULL) && (cb->done == true)) {
+ IPADBG("SMMU CB type %d already initialized\n", cb_type);
+ return 0;
+ }
switch (cb_type) {
case IPA_SMMU_CB_AP:
+ ipa3_ctx->pdev = &ipa3_ctx->master_pdev->dev;
return ipa_smmu_ap_cb_probe(dev);
case IPA_SMMU_CB_WLAN:
case IPA_SMMU_CB_WLAN1:
@@ -10558,6 +10679,7 @@
case IPA_SMMU_CB_ETH1:
return ipa_smmu_perph_cb_probe(dev, cb_type);
case IPA_SMMU_CB_UC:
+ ipa3_ctx->uc_pdev = &ipa3_ctx->master_pdev->dev;
return ipa_smmu_uc_cb_probe(dev);
case IPA_SMMU_CB_11AD:
return ipa_smmu_11ad_cb_probe(dev);
@@ -10572,16 +10694,15 @@
struct ipa_smmu_cb_ctx *cb;
int i, result;
- ipa3_ctx->pdev = &ipa3_ctx->master_pdev->dev;
- ipa3_ctx->uc_pdev = &ipa3_ctx->master_pdev->dev;
-
if (smmu_info.arm_smmu) {
IPADBG("smmu is enabled\n");
for (i = 0; i < IPA_SMMU_CB_MAX; i++) {
cb = ipa3_get_smmu_ctx(i);
result = ipa_smmu_cb_probe(cb->dev, i);
- if (result)
+ if (result) {
IPAERR("probe failed for cb %d\n", i);
+ return result;
+ }
}
} else {
IPADBG("smmu is disabled\n");
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 00ae2c5..7825c0c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -100,6 +100,7 @@
static struct sk_buff *ipa3_get_skb_ipa_rx(unsigned int len, gfp_t flags);
static void ipa3_replenish_wlan_rx_cache(struct ipa3_sys_context *sys);
static void ipa3_replenish_rx_cache(struct ipa3_sys_context *sys);
+static void ipa3_first_replenish_rx_cache(struct ipa3_sys_context *sys);
static void ipa3_replenish_rx_work_func(struct work_struct *work);
static void ipa3_fast_replenish_rx_cache(struct ipa3_sys_context *sys);
static void ipa3_replenish_rx_page_cache(struct ipa3_sys_context *sys);
@@ -1523,7 +1524,7 @@
ipa3_ctx->ipa_wan_skb_page) {
ipa3_replenish_rx_page_recycle(ep->sys);
} else
- ipa3_replenish_rx_cache(ep->sys);
+ ipa3_first_replenish_rx_cache(ep->sys);
for (i = 0; i < GSI_VEID_MAX; i++)
INIT_LIST_HEAD(&ep->sys->pending_pkts[i]);
}
@@ -2822,6 +2823,111 @@
return;
}
+/**
+ * ipa3_first_replenish_rx_cache() - Replenish the Rx packets cache for the first time.
+ *
+ * The function allocates buffers in the rx_pkt_wrapper_cache cache until there
+ * are IPA_RX_POOL_CEIL buffers in the cache.
+ * - Allocate a buffer in the cache
+ * - Initialized the packets link
+ * - Initialize the packets work struct
+ * - Allocate the packets socket buffer (skb)
+ * - Fill the packets skb with data
+ * - Make the packet DMAable
+ * - Add the packet to the system pipe linked list
+ */
+static void ipa3_first_replenish_rx_cache(struct ipa3_sys_context *sys)
+{
+ void *ptr;
+ struct ipa3_rx_pkt_wrapper *rx_pkt;
+ int ret;
+ int idx = 0;
+ int rx_len_cached = 0;
+ struct gsi_xfer_elem gsi_xfer_elem_array[IPA_REPL_XFER_MAX];
+ gfp_t flag = GFP_NOWAIT | __GFP_NOWARN;
+
+ rx_len_cached = sys->len;
+
+ /* start replenish only when buffers go lower than the threshold */
+ if (sys->rx_pool_sz - sys->len < IPA_REPL_XFER_THRESH)
+ return;
+
+ while (rx_len_cached < sys->rx_pool_sz) {
+ rx_pkt = kmem_cache_zalloc(ipa3_ctx->rx_pkt_wrapper_cache,
+ flag);
+ if (!rx_pkt) {
+ IPAERR("failed to alloc cache\n");
+ goto fail_kmem_cache_alloc;
+ }
+
+ INIT_WORK(&rx_pkt->work, ipa3_wq_rx_avail);
+ rx_pkt->sys = sys;
+
+ rx_pkt->data.skb = sys->get_skb(sys->rx_buff_sz, flag);
+ if (rx_pkt->data.skb == NULL) {
+ IPAERR("failed to alloc skb\n");
+ goto fail_skb_alloc;
+ }
+ ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
+ rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
+ sys->rx_buff_sz,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
+ IPAERR("dma_map_single failure %pK for %pK\n",
+ (void *)rx_pkt->data.dma_addr, ptr);
+ goto fail_dma_mapping;
+ }
+
+ gsi_xfer_elem_array[idx].addr = rx_pkt->data.dma_addr;
+ gsi_xfer_elem_array[idx].len = sys->rx_buff_sz;
+ gsi_xfer_elem_array[idx].flags = GSI_XFER_FLAG_EOT;
+ gsi_xfer_elem_array[idx].flags |= GSI_XFER_FLAG_EOB;
+ gsi_xfer_elem_array[idx].flags |= GSI_XFER_FLAG_BEI;
+ gsi_xfer_elem_array[idx].type = GSI_XFER_ELEM_DATA;
+ gsi_xfer_elem_array[idx].xfer_user_data = rx_pkt;
+ idx++;
+ rx_len_cached++;
+ /*
+ * gsi_xfer_elem_buffer has a size of IPA_REPL_XFER_MAX.
+ * If this size is reached we need to queue the xfers.
+ */
+ if (idx == IPA_REPL_XFER_MAX) {
+ ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, idx,
+ gsi_xfer_elem_array, false);
+ if (ret != GSI_STATUS_SUCCESS) {
+ /* we don't expect this will happen */
+ IPAERR("failed to provide buffer: %d\n", ret);
+ WARN_ON(1);
+ break;
+ }
+ idx = 0;
+ }
+ }
+ goto done;
+
+fail_dma_mapping:
+ sys->free_skb(rx_pkt->data.skb);
+fail_skb_alloc:
+ kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt);
+fail_kmem_cache_alloc:
+ /* Ensuring minimum buffers are submitted to HW */
+ if (rx_len_cached < IPA_REPL_XFER_THRESH) {
+ queue_delayed_work(sys->wq, &sys->replenish_rx_work,
+ msecs_to_jiffies(1));
+ return;
+ }
+done:
+ /* only ring doorbell once here */
+ ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, idx,
+ gsi_xfer_elem_array, true);
+ if (ret == GSI_STATUS_SUCCESS) {
+ sys->len = rx_len_cached;
+ } else {
+ /* we don't expect this will happen */
+ IPAERR("failed to provide buffer: %d\n", ret);
+ WARN_ON(1);
+ }
+}
/**
* ipa3_replenish_rx_cache() - Replenish the Rx packets cache.
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index f0eda95..0f95e4d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -602,13 +602,22 @@
mem_size = entry->is_lcl ? IPA_MEM_PART(apps_hdr_size) : IPA_MEM_PART(apps_hdr_size_ddr);
if (list_empty(&htbl->head_free_offset_list[bin])) {
- /* if header does not fit to table, place it in DDR */
- if (htbl->end + ipa_hdr_bin_sz[bin] > mem_size) {
+ /*
+ * In case of a local header entry,
+ * first iteration will check against SRAM partition space,
+ * and the second iteration will check against DDR partition space.
+ * In case of a system header entry, the loop will iterate only once,
+ * and check against DDR partition space.
+ */
+ while (htbl->end + ipa_hdr_bin_sz[bin] > mem_size) {
if (entry->is_lcl) {
+ /* if header does not fit to SRAM table, place it in DDR */
htbl = &ipa3_ctx->hdr_tbl[HDR_TBL_SYS];
mem_size = IPA_MEM_PART(apps_hdr_size_ddr);
entry->is_lcl = false;
} else {
+ /* if the entry is intended to be in DDR,
+ and there is no space -> error */
IPAERR("No space in DDR header buffer! Requested: %d Left: %d\n",
ipa_hdr_bin_sz[bin], mem_size - htbl->end);
goto bad_hdr_len;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 98f92f0..595c901 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -618,6 +618,7 @@
u32 va_end;
bool shared;
bool is_cache_coherent;
+ bool done;
};
/**
@@ -2387,6 +2388,8 @@
struct mutex act_tbl_lock;
int uc_act_tbl_total;
int uc_act_tbl_next_index;
+ int ipa_pil_load;
+
};
struct ipa3_plat_drv_res {
@@ -3616,4 +3619,10 @@
void ipa3_update_mhi_ctrl_state(u8 state, bool set);
/* Send MHI endpoint info to modem using QMI indication message */
int ipa_send_mhi_endp_ind_to_modem(void);
+
+/*
+ * To pass macsec mapping to the IPACM
+ */
+int ipa3_send_macsec_info(enum ipa_macsec_event event_type, struct ipa_macsec_map *map);
+
#endif /* _IPA3_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
index b4c2b7a..ceb6051 100644
--- a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
@@ -30,6 +30,8 @@
pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d EXIT\n", __func__, __LINE__)
#define TETH_ERR(fmt, args...) \
pr_err(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
+#define TETH_ERR_RL(fmt, args...) \
+ pr_err_ratelimited_ipa(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
enum ipa_num_teth_iface {
IPA_TETH_IFACE_1 = 0,
@@ -76,7 +78,7 @@
return;
}
- TETH_ERR("Unexpected exception packet from USB, dropping packet\n");
+ TETH_ERR_RL("Unexpected exception packet from USB, dropping packet\n");
dev_kfree_skb_any(skb);
TETH_DBG_FUNC_EXIT();
}