Loading drivers/platform/msm/ipa/ipa_v3/ipa.c +1 −0 Original line number Diff line number Diff line Loading @@ -6911,6 +6911,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) smmu_info.present[IPA_SMMU_CB_AP] = true; ipa3_ctx->pdev = dev; cb->next_addr = cb->va_end; return 0; } Loading drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +145 −12 Original line number Diff line number Diff line /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2019, 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 Loading Loading @@ -503,6 +503,38 @@ int ipa3_wdi_init(void) return 0; } static int ipa_create_ap_smmu_mapping_pa(phys_addr_t pa, size_t len, bool device, unsigned long *iova) { struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP); unsigned long va = roundup(cb->next_addr, PAGE_SIZE); int prot = IOMMU_READ | IOMMU_WRITE; size_t true_len = roundup(len + pa - rounddown(pa, PAGE_SIZE), PAGE_SIZE); int ret; if (!cb->valid) { IPAERR("No SMMU CB setup\n"); return -EINVAL; } if (len > PAGE_SIZE) va = roundup(cb->next_addr, len); ret = ipa3_iommu_map(cb->mapping->domain, va, rounddown(pa, PAGE_SIZE), true_len, device ? (prot | IOMMU_MMIO) : prot); if (ret) { IPAERR("iommu map failed for pa=%pa len=%zu\n", &pa, true_len); return -EINVAL; } ipa3_ctx->wdi_map_cnt++; cb->next_addr = va + true_len; *iova = va + pa - rounddown(pa, PAGE_SIZE); return 0; } static int ipa_create_uc_smmu_mapping_pa(phys_addr_t pa, size_t len, bool device, unsigned long *iova) { Loading Loading @@ -532,6 +564,67 @@ static int ipa_create_uc_smmu_mapping_pa(phys_addr_t pa, size_t len, return 0; } static int ipa_create_ap_smmu_mapping_sgt(struct sg_table *sgt, unsigned long *iova) { struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP); unsigned long va = roundup(cb->next_addr, PAGE_SIZE); int prot = IOMMU_READ | IOMMU_WRITE; int ret, i; struct scatterlist *sg; unsigned long start_iova = va; phys_addr_t phys; size_t len = 0; int count = 0; if (!cb->valid) { IPAERR("No SMMU CB setup\n"); return -EINVAL; } if (!sgt) { IPAERR("Bad parameters, scatter / gather list is NULL\n"); return -EINVAL; } for_each_sg(sgt->sgl, sg, sgt->nents, i) { /* directly get sg_tbl PA from wlan-driver */ len += PAGE_ALIGN(sg->offset + sg->length); } if (len > PAGE_SIZE) { va = roundup(cb->next_addr, roundup_pow_of_two(len)); start_iova = va; } for_each_sg(sgt->sgl, sg, sgt->nents, i) { /* directly get sg_tbl PA from wlan-driver */ phys = sg->dma_address; len = PAGE_ALIGN(sg->offset + sg->length); ret = ipa3_iommu_map(cb->mapping->domain, va, phys, len, prot); if (ret) { IPAERR("iommu map failed for pa=%pa len=%zu\n", &phys, len); goto bad_mapping; } va += len; ipa3_ctx->wdi_map_cnt++; count++; } cb->next_addr = va; *iova = start_iova; return 0; bad_mapping: for_each_sg(sgt->sgl, sg, count, i) iommu_unmap(cb->mapping->domain, sg_dma_address(sg), sg_dma_len(sg)); return -EINVAL; } static int ipa_create_uc_smmu_mapping_sgt(struct sg_table *sgt, unsigned long *iova) { Loading Loading @@ -582,6 +675,43 @@ static int ipa_create_uc_smmu_mapping_sgt(struct sg_table *sgt, return -EINVAL; } static void ipa_release_ap_smmu_mappings(enum ipa_client_type client) { struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP); int i, j, start, end; if (IPA_CLIENT_IS_CONS(client)) { start = IPA_WDI_TX_RING_RES; if (ipa3_ctx->ipa_wdi3_over_gsi) end = IPA_WDI_TX_DB_RES; else end = IPA_WDI_CE_DB_RES; } else { start = IPA_WDI_RX_RING_RES; if (ipa3_ctx->ipa_wdi2 || ipa3_ctx->ipa_wdi3_over_gsi) end = IPA_WDI_RX_COMP_RING_WP_RES; else end = IPA_WDI_RX_RING_RP_RES; } for (i = start; i <= end; i++) { if (wdi_res[i].valid) { for (j = 0; j < wdi_res[i].nents; j++) { iommu_unmap(cb->mapping->domain, wdi_res[i].res[j].iova, wdi_res[i].res[j].size); ipa3_ctx->wdi_map_cnt--; } kfree(wdi_res[i].res); wdi_res[i].valid = false; } } if (ipa3_ctx->wdi_map_cnt == 0) cb->next_addr = cb->va_end; } static void ipa_release_uc_smmu_mappings(enum ipa_client_type client) { struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC); Loading Loading @@ -757,9 +887,11 @@ int ipa_create_gsi_smmu_mapping(int res_idx, bool wlan_smmu_en, /* no SMMU on WLAN but SMMU on IPA */ if (!wlan_smmu_en && !ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) { if (ipa3_smmu_map_peer_buff(*iova, pa, len, sgt, IPA_SMMU_CB_WLAN)) { IPAERR("Fail to create mapping res %d\n", res_idx); if (ipa_create_ap_smmu_mapping_pa(pa, len, (res_idx == IPA_WDI_CE_DB_RES) ? true : false, iova)) { IPAERR("Fail to create mapping res %d\n", res_idx); return -EFAULT; } ipa_save_uc_smmu_mapping_pa(res_idx, pa, *iova, len); Loading @@ -771,8 +903,10 @@ int ipa_create_gsi_smmu_mapping(int res_idx, bool wlan_smmu_en, case IPA_WDI_RX_RING_RP_RES: case IPA_WDI_RX_COMP_RING_WP_RES: case IPA_WDI_CE_DB_RES: if (ipa3_smmu_map_peer_buff(*iova, pa, len, sgt, IPA_SMMU_CB_WLAN)) { case IPA_WDI_TX_DB_RES: if (ipa_create_ap_smmu_mapping_pa(pa, len, (res_idx == IPA_WDI_CE_DB_RES) ? true : false, iova)) { IPAERR("Fail to create mapping res %d\n", res_idx); return -EFAULT; Loading @@ -783,8 +917,7 @@ int ipa_create_gsi_smmu_mapping(int res_idx, bool wlan_smmu_en, case IPA_WDI_RX_COMP_RING_RES: case IPA_WDI_TX_RING_RES: case IPA_WDI_CE_RING_RES: if (ipa3_smmu_map_peer_reg(pa, true, IPA_SMMU_CB_WLAN)) { if (ipa_create_ap_smmu_mapping_sgt(sgt, iova)) { IPAERR("Fail to create mapping res %d\n", res_idx); return -EFAULT; Loading Loading @@ -1310,7 +1443,7 @@ int ipa3_connect_gsi_wdi_pipe(struct ipa_wdi_in_params *in, ipa_cfg_ep_fail: memset(&ipa3_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa3_ep_context)); gsi_timeout: ipa_release_uc_smmu_mappings(in->sys.client); ipa_release_ap_smmu_mappings(in->sys.client); IPA_ACTIVE_CLIENTS_DEC_EP(in->sys.client); fail: return result; Loading Loading @@ -1870,7 +2003,7 @@ int ipa3_disconnect_gsi_wdi_pipe(u32 clnt_hdl) result); goto fail_dealloc_channel; } ipa_release_uc_smmu_mappings(clnt_hdl); ipa_release_ap_smmu_mappings(clnt_hdl); /* for AP+STA stats update */ if (ipa3_ctx->uc_wdi_ctx.stats_notify) Loading drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c +156 −4 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ static int ipa3_setup_wdi3_gsi_channel(u8 is_smmu_enabled, const struct ipa_gsi_ep_config *gsi_ep_info; int result, len; unsigned long va; uint32_t addr_low, addr_high; if (!info || !info_smmu || !ep) { IPAERR("invalid input\n"); Loading Loading @@ -217,23 +218,131 @@ static int ipa3_setup_wdi3_gsi_channel(u8 is_smmu_enabled, IPAERR("failed to write evt ring scratch\n"); goto fail_write_scratch; } /* write event ring db address */ gsi_wdi3_write_evt_ring_db(ep->gsi_evt_ring_hdl, (u32)info->event_ring_doorbell_pa, if (!is_smmu_enabled) { IPADBG("smmu disabled\n"); if (info->is_evt_rn_db_pcie_addr == true) IPADBG_LOW("is_evt_rn_db_pcie_addr is PCIE addr\n"); else IPADBG_LOW("is_evt_rn_db_pcie_addr is DDR addr\n"); IPADBG_LOW("LSB 0x%x\n", (u32)info->event_ring_doorbell_pa); IPADBG_LOW("MSB 0x%x\n", (u32)((u64)info->event_ring_doorbell_pa >> 32)); } else { IPADBG("smmu enabled\n"); if (info_smmu->is_evt_rn_db_pcie_addr == true) IPADBG_LOW("is_evt_rn_db_pcie_addr is PCIE addr\n"); else IPADBG_LOW("is_evt_rn_db_pcie_addr is DDR addr\n"); IPADBG_LOW("LSB 0x%x\n", (u32)info_smmu->event_ring_doorbell_pa); IPADBG_LOW("MSB 0x%x\n", (u32)((u64)info_smmu->event_ring_doorbell_pa >> 32)); } if (!is_smmu_enabled) { addr_low = (u32)info->event_ring_doorbell_pa; addr_high = (u32)((u64)info->event_ring_doorbell_pa >> 32); } else { if (dir == IPA_WDI3_TX_DIR) { if (ipa_create_gsi_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"); result = -EFAULT; goto fail_write_scratch; } } else { if (ipa_create_gsi_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"); result = -EFAULT; goto fail_write_scratch; } } addr_low = (u32)va; addr_high = (u32)((u64)va >> 32); } /* * Arch specific: * pcie addr which are not via smmu, use pa directly! * pcie and DDR via 2 different port * assert bit 40 to indicate it is pcie addr * WDI-3.0, MSM --> pcie via smmu * WDI-3.0, MDM --> pcie not via smmu + dual port * assert bit 40 in case */ if (!ipa3_is_msm_device() && is_smmu_enabled) { /* * Ir-respective of smmu enabled don't use IOVA addr * since pcie not via smmu in MDM's */ if (info_smmu->is_evt_rn_db_pcie_addr == true) { addr_low = (u32)info_smmu->event_ring_doorbell_pa; addr_high = (u32)((u64)info_smmu->event_ring_doorbell_pa >> 32); } } /* * GSI recomendation to set bit-40 for (mdm targets && pcie addr) * from wdi-3.0 interface document */ if (!is_smmu_enabled) { if (!ipa3_is_msm_device() && info->is_evt_rn_db_pcie_addr) addr_high |= (1 << 8); } else { if (!ipa3_is_msm_device() && info_smmu->is_evt_rn_db_pcie_addr) addr_high |= (1 << 8); } gsi_wdi3_write_evt_ring_db(ep->gsi_evt_ring_hdl, addr_low, addr_high); /* write channel scratch */ memset(&ch_scratch, 0, sizeof(ch_scratch)); ch_scratch.wdi3.update_rp_moderation_threshold = UPDATE_RP_MODERATION_THRESHOLD; if (dir == IPA_WDI3_RX_DIR) { if (!is_smmu_enabled) ch_scratch.wdi3.rx_pkt_offset = info->pkt_offset; else ch_scratch.wdi3.rx_pkt_offset = info_smmu->pkt_offset; /* this metadata reg offset need to be in words */ ch_scratch.wdi3.endp_metadata_reg_offset = ipahal_get_reg_mn_ofst(IPA_ENDP_INIT_HDR_METADATA_n, 0, gsi_ep_info->ipa_ep_num) / 4; } if (!is_smmu_enabled) { IPADBG_LOW("smmu disabled\n"); if (info->is_txr_rn_db_pcie_addr == true) IPADBG_LOW("is_txr_rn_db_pcie_addr is PCIE addr\n"); else IPADBG_LOW("is_txr_rn_db_pcie_addr is DDR addr\n"); IPADBG_LOW("LSB 0x%x\n", (u32)info->transfer_ring_doorbell_pa); IPADBG_LOW("MSB 0x%x\n", (u32)((u64)info->transfer_ring_doorbell_pa >> 32)); } else { IPADBG_LOW("smmu eabled\n"); if (info_smmu->is_txr_rn_db_pcie_addr == true) IPADBG_LOW("is_txr_rn_db_pcie_addr is PCIE addr\n"); else IPADBG_LOW("is_txr_rn_db_pcie_addr is DDR addr\n"); IPADBG_LOW("LSB 0x%x\n", (u32)info_smmu->transfer_ring_doorbell_pa); IPADBG_LOW("MSB 0x%x\n", (u32)((u64)info_smmu->transfer_ring_doorbell_pa >> 32)); } if (!is_smmu_enabled) { ch_scratch.wdi3.wifi_rp_address_low = (u32)info->transfer_ring_doorbell_pa; Loading Loading @@ -268,6 +377,49 @@ static int ipa3_setup_wdi3_gsi_channel(u8 is_smmu_enabled, (u32)((u64)va >> 32); } } /* * Arch specific: * pcie addr which are not via smmu, use pa directly! * pcie and DDR via 2 different port * assert bit 40 to indicate it is pcie addr * WDI-3.0, MSM --> pcie via smmu * WDI-3.0, MDM --> pcie not via smmu + dual port * assert bit 40 in case */ if (!ipa3_is_msm_device() && is_smmu_enabled) { /* * Ir-respective of smmu enabled don't use IOVA addr * since pcie not via smmu in MDM's */ if (info_smmu->is_txr_rn_db_pcie_addr == true) { ch_scratch.wdi3.wifi_rp_address_low = (u32)info_smmu->transfer_ring_doorbell_pa; ch_scratch.wdi3.wifi_rp_address_high = (u32)((u64)info_smmu->transfer_ring_doorbell_pa >> 32); } } /* * GSI recomendation to set bit-40 for(mdm targets && pcie addr) * from wdi-3.0 interface document */ if (!is_smmu_enabled) { if (!ipa3_is_msm_device() && info->is_txr_rn_db_pcie_addr) ch_scratch.wdi3.wifi_rp_address_high = (u32)((u32)ch_scratch.wdi3.wifi_rp_address_high | (1 << 8)); } else { if (!ipa3_is_msm_device() && info_smmu->is_txr_rn_db_pcie_addr) ch_scratch.wdi3.wifi_rp_address_high = (u32)((u32)ch_scratch.wdi3.wifi_rp_address_high | (1 << 8)); } result = gsi_write_channel_scratch(ep->gsi_chan_hdl, ch_scratch); if (result != GSI_STATUS_SUCCESS) { IPAERR("failed to write evt ring scratch\n"); Loading include/linux/ipa_wdi3.h +9 −1 Original line number Diff line number Diff line /* Copyright (c) 2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2018-2019, 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 Loading Loading @@ -104,10 +104,12 @@ struct ipa_wdi_reg_intf_in_params { * @transfer_ring_size: size of the transfer ring * @transfer_ring_doorbell_pa: physical address of the doorbell that IPA uC will update the tailpointer of the transfer ring * @is_txr_rn_db_pcie_addr: Bool indicated txr ring DB is pcie or not * @event_ring_base_pa: physical address of the base of the event ring * @event_ring_size: event ring size * @event_ring_doorbell_pa: physical address of the doorbell that IPA uC will update the headpointer of the event ring * @is_evt_rn_db_pcie_addr: Bool indicated evt ring DB is pcie or not * @num_pkt_buffers: Number of pkt buffers allocated. The size of the event ring and the transfer ring has to be atleast ( num_pkt_buffers + 1) * @pkt_offset: packet offset (wdi header length) Loading @@ -120,10 +122,12 @@ struct ipa_wdi_pipe_setup_info { phys_addr_t transfer_ring_base_pa; u32 transfer_ring_size; phys_addr_t transfer_ring_doorbell_pa; bool is_txr_rn_db_pcie_addr; phys_addr_t event_ring_base_pa; u32 event_ring_size; phys_addr_t event_ring_doorbell_pa; bool is_evt_rn_db_pcie_addr; u16 num_pkt_buffers; u16 pkt_offset; Loading @@ -139,10 +143,12 @@ struct ipa_wdi_pipe_setup_info { * @transfer_ring_size: size of the transfer ring * @transfer_ring_doorbell_pa: physical address of the doorbell that IPA uC will update the tailpointer of the transfer ring * @is_txr_rn_db_pcie_addr: Bool indicated txr ring DB is pcie or not * @event_ring_base_pa: physical address of the base of the event ring * @event_ring_size: event ring size * @event_ring_doorbell_pa: physical address of the doorbell that IPA uC will update the headpointer of the event ring * @is_evt_rn_db_pcie_addr: Bool indicated evt ring DB is pcie or not * @num_pkt_buffers: Number of pkt buffers allocated. The size of the event ring and the transfer ring has to be atleast ( num_pkt_buffers + 1) * @pkt_offset: packet offset (wdi header length) Loading @@ -155,10 +161,12 @@ struct ipa_wdi_pipe_setup_info_smmu { struct sg_table transfer_ring_base; u32 transfer_ring_size; phys_addr_t transfer_ring_doorbell_pa; bool is_txr_rn_db_pcie_addr; struct sg_table event_ring_base; u32 event_ring_size; phys_addr_t event_ring_doorbell_pa; bool is_evt_rn_db_pcie_addr; u16 num_pkt_buffers; u16 pkt_offset; Loading Loading
drivers/platform/msm/ipa/ipa_v3/ipa.c +1 −0 Original line number Diff line number Diff line Loading @@ -6911,6 +6911,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) smmu_info.present[IPA_SMMU_CB_AP] = true; ipa3_ctx->pdev = dev; cb->next_addr = cb->va_end; return 0; } Loading
drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +145 −12 Original line number Diff line number Diff line /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2019, 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 Loading Loading @@ -503,6 +503,38 @@ int ipa3_wdi_init(void) return 0; } static int ipa_create_ap_smmu_mapping_pa(phys_addr_t pa, size_t len, bool device, unsigned long *iova) { struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP); unsigned long va = roundup(cb->next_addr, PAGE_SIZE); int prot = IOMMU_READ | IOMMU_WRITE; size_t true_len = roundup(len + pa - rounddown(pa, PAGE_SIZE), PAGE_SIZE); int ret; if (!cb->valid) { IPAERR("No SMMU CB setup\n"); return -EINVAL; } if (len > PAGE_SIZE) va = roundup(cb->next_addr, len); ret = ipa3_iommu_map(cb->mapping->domain, va, rounddown(pa, PAGE_SIZE), true_len, device ? (prot | IOMMU_MMIO) : prot); if (ret) { IPAERR("iommu map failed for pa=%pa len=%zu\n", &pa, true_len); return -EINVAL; } ipa3_ctx->wdi_map_cnt++; cb->next_addr = va + true_len; *iova = va + pa - rounddown(pa, PAGE_SIZE); return 0; } static int ipa_create_uc_smmu_mapping_pa(phys_addr_t pa, size_t len, bool device, unsigned long *iova) { Loading Loading @@ -532,6 +564,67 @@ static int ipa_create_uc_smmu_mapping_pa(phys_addr_t pa, size_t len, return 0; } static int ipa_create_ap_smmu_mapping_sgt(struct sg_table *sgt, unsigned long *iova) { struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP); unsigned long va = roundup(cb->next_addr, PAGE_SIZE); int prot = IOMMU_READ | IOMMU_WRITE; int ret, i; struct scatterlist *sg; unsigned long start_iova = va; phys_addr_t phys; size_t len = 0; int count = 0; if (!cb->valid) { IPAERR("No SMMU CB setup\n"); return -EINVAL; } if (!sgt) { IPAERR("Bad parameters, scatter / gather list is NULL\n"); return -EINVAL; } for_each_sg(sgt->sgl, sg, sgt->nents, i) { /* directly get sg_tbl PA from wlan-driver */ len += PAGE_ALIGN(sg->offset + sg->length); } if (len > PAGE_SIZE) { va = roundup(cb->next_addr, roundup_pow_of_two(len)); start_iova = va; } for_each_sg(sgt->sgl, sg, sgt->nents, i) { /* directly get sg_tbl PA from wlan-driver */ phys = sg->dma_address; len = PAGE_ALIGN(sg->offset + sg->length); ret = ipa3_iommu_map(cb->mapping->domain, va, phys, len, prot); if (ret) { IPAERR("iommu map failed for pa=%pa len=%zu\n", &phys, len); goto bad_mapping; } va += len; ipa3_ctx->wdi_map_cnt++; count++; } cb->next_addr = va; *iova = start_iova; return 0; bad_mapping: for_each_sg(sgt->sgl, sg, count, i) iommu_unmap(cb->mapping->domain, sg_dma_address(sg), sg_dma_len(sg)); return -EINVAL; } static int ipa_create_uc_smmu_mapping_sgt(struct sg_table *sgt, unsigned long *iova) { Loading Loading @@ -582,6 +675,43 @@ static int ipa_create_uc_smmu_mapping_sgt(struct sg_table *sgt, return -EINVAL; } static void ipa_release_ap_smmu_mappings(enum ipa_client_type client) { struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP); int i, j, start, end; if (IPA_CLIENT_IS_CONS(client)) { start = IPA_WDI_TX_RING_RES; if (ipa3_ctx->ipa_wdi3_over_gsi) end = IPA_WDI_TX_DB_RES; else end = IPA_WDI_CE_DB_RES; } else { start = IPA_WDI_RX_RING_RES; if (ipa3_ctx->ipa_wdi2 || ipa3_ctx->ipa_wdi3_over_gsi) end = IPA_WDI_RX_COMP_RING_WP_RES; else end = IPA_WDI_RX_RING_RP_RES; } for (i = start; i <= end; i++) { if (wdi_res[i].valid) { for (j = 0; j < wdi_res[i].nents; j++) { iommu_unmap(cb->mapping->domain, wdi_res[i].res[j].iova, wdi_res[i].res[j].size); ipa3_ctx->wdi_map_cnt--; } kfree(wdi_res[i].res); wdi_res[i].valid = false; } } if (ipa3_ctx->wdi_map_cnt == 0) cb->next_addr = cb->va_end; } static void ipa_release_uc_smmu_mappings(enum ipa_client_type client) { struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_UC); Loading Loading @@ -757,9 +887,11 @@ int ipa_create_gsi_smmu_mapping(int res_idx, bool wlan_smmu_en, /* no SMMU on WLAN but SMMU on IPA */ if (!wlan_smmu_en && !ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) { if (ipa3_smmu_map_peer_buff(*iova, pa, len, sgt, IPA_SMMU_CB_WLAN)) { IPAERR("Fail to create mapping res %d\n", res_idx); if (ipa_create_ap_smmu_mapping_pa(pa, len, (res_idx == IPA_WDI_CE_DB_RES) ? true : false, iova)) { IPAERR("Fail to create mapping res %d\n", res_idx); return -EFAULT; } ipa_save_uc_smmu_mapping_pa(res_idx, pa, *iova, len); Loading @@ -771,8 +903,10 @@ int ipa_create_gsi_smmu_mapping(int res_idx, bool wlan_smmu_en, case IPA_WDI_RX_RING_RP_RES: case IPA_WDI_RX_COMP_RING_WP_RES: case IPA_WDI_CE_DB_RES: if (ipa3_smmu_map_peer_buff(*iova, pa, len, sgt, IPA_SMMU_CB_WLAN)) { case IPA_WDI_TX_DB_RES: if (ipa_create_ap_smmu_mapping_pa(pa, len, (res_idx == IPA_WDI_CE_DB_RES) ? true : false, iova)) { IPAERR("Fail to create mapping res %d\n", res_idx); return -EFAULT; Loading @@ -783,8 +917,7 @@ int ipa_create_gsi_smmu_mapping(int res_idx, bool wlan_smmu_en, case IPA_WDI_RX_COMP_RING_RES: case IPA_WDI_TX_RING_RES: case IPA_WDI_CE_RING_RES: if (ipa3_smmu_map_peer_reg(pa, true, IPA_SMMU_CB_WLAN)) { if (ipa_create_ap_smmu_mapping_sgt(sgt, iova)) { IPAERR("Fail to create mapping res %d\n", res_idx); return -EFAULT; Loading Loading @@ -1310,7 +1443,7 @@ int ipa3_connect_gsi_wdi_pipe(struct ipa_wdi_in_params *in, ipa_cfg_ep_fail: memset(&ipa3_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa3_ep_context)); gsi_timeout: ipa_release_uc_smmu_mappings(in->sys.client); ipa_release_ap_smmu_mappings(in->sys.client); IPA_ACTIVE_CLIENTS_DEC_EP(in->sys.client); fail: return result; Loading Loading @@ -1870,7 +2003,7 @@ int ipa3_disconnect_gsi_wdi_pipe(u32 clnt_hdl) result); goto fail_dealloc_channel; } ipa_release_uc_smmu_mappings(clnt_hdl); ipa_release_ap_smmu_mappings(clnt_hdl); /* for AP+STA stats update */ if (ipa3_ctx->uc_wdi_ctx.stats_notify) Loading
drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c +156 −4 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ static int ipa3_setup_wdi3_gsi_channel(u8 is_smmu_enabled, const struct ipa_gsi_ep_config *gsi_ep_info; int result, len; unsigned long va; uint32_t addr_low, addr_high; if (!info || !info_smmu || !ep) { IPAERR("invalid input\n"); Loading Loading @@ -217,23 +218,131 @@ static int ipa3_setup_wdi3_gsi_channel(u8 is_smmu_enabled, IPAERR("failed to write evt ring scratch\n"); goto fail_write_scratch; } /* write event ring db address */ gsi_wdi3_write_evt_ring_db(ep->gsi_evt_ring_hdl, (u32)info->event_ring_doorbell_pa, if (!is_smmu_enabled) { IPADBG("smmu disabled\n"); if (info->is_evt_rn_db_pcie_addr == true) IPADBG_LOW("is_evt_rn_db_pcie_addr is PCIE addr\n"); else IPADBG_LOW("is_evt_rn_db_pcie_addr is DDR addr\n"); IPADBG_LOW("LSB 0x%x\n", (u32)info->event_ring_doorbell_pa); IPADBG_LOW("MSB 0x%x\n", (u32)((u64)info->event_ring_doorbell_pa >> 32)); } else { IPADBG("smmu enabled\n"); if (info_smmu->is_evt_rn_db_pcie_addr == true) IPADBG_LOW("is_evt_rn_db_pcie_addr is PCIE addr\n"); else IPADBG_LOW("is_evt_rn_db_pcie_addr is DDR addr\n"); IPADBG_LOW("LSB 0x%x\n", (u32)info_smmu->event_ring_doorbell_pa); IPADBG_LOW("MSB 0x%x\n", (u32)((u64)info_smmu->event_ring_doorbell_pa >> 32)); } if (!is_smmu_enabled) { addr_low = (u32)info->event_ring_doorbell_pa; addr_high = (u32)((u64)info->event_ring_doorbell_pa >> 32); } else { if (dir == IPA_WDI3_TX_DIR) { if (ipa_create_gsi_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"); result = -EFAULT; goto fail_write_scratch; } } else { if (ipa_create_gsi_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"); result = -EFAULT; goto fail_write_scratch; } } addr_low = (u32)va; addr_high = (u32)((u64)va >> 32); } /* * Arch specific: * pcie addr which are not via smmu, use pa directly! * pcie and DDR via 2 different port * assert bit 40 to indicate it is pcie addr * WDI-3.0, MSM --> pcie via smmu * WDI-3.0, MDM --> pcie not via smmu + dual port * assert bit 40 in case */ if (!ipa3_is_msm_device() && is_smmu_enabled) { /* * Ir-respective of smmu enabled don't use IOVA addr * since pcie not via smmu in MDM's */ if (info_smmu->is_evt_rn_db_pcie_addr == true) { addr_low = (u32)info_smmu->event_ring_doorbell_pa; addr_high = (u32)((u64)info_smmu->event_ring_doorbell_pa >> 32); } } /* * GSI recomendation to set bit-40 for (mdm targets && pcie addr) * from wdi-3.0 interface document */ if (!is_smmu_enabled) { if (!ipa3_is_msm_device() && info->is_evt_rn_db_pcie_addr) addr_high |= (1 << 8); } else { if (!ipa3_is_msm_device() && info_smmu->is_evt_rn_db_pcie_addr) addr_high |= (1 << 8); } gsi_wdi3_write_evt_ring_db(ep->gsi_evt_ring_hdl, addr_low, addr_high); /* write channel scratch */ memset(&ch_scratch, 0, sizeof(ch_scratch)); ch_scratch.wdi3.update_rp_moderation_threshold = UPDATE_RP_MODERATION_THRESHOLD; if (dir == IPA_WDI3_RX_DIR) { if (!is_smmu_enabled) ch_scratch.wdi3.rx_pkt_offset = info->pkt_offset; else ch_scratch.wdi3.rx_pkt_offset = info_smmu->pkt_offset; /* this metadata reg offset need to be in words */ ch_scratch.wdi3.endp_metadata_reg_offset = ipahal_get_reg_mn_ofst(IPA_ENDP_INIT_HDR_METADATA_n, 0, gsi_ep_info->ipa_ep_num) / 4; } if (!is_smmu_enabled) { IPADBG_LOW("smmu disabled\n"); if (info->is_txr_rn_db_pcie_addr == true) IPADBG_LOW("is_txr_rn_db_pcie_addr is PCIE addr\n"); else IPADBG_LOW("is_txr_rn_db_pcie_addr is DDR addr\n"); IPADBG_LOW("LSB 0x%x\n", (u32)info->transfer_ring_doorbell_pa); IPADBG_LOW("MSB 0x%x\n", (u32)((u64)info->transfer_ring_doorbell_pa >> 32)); } else { IPADBG_LOW("smmu eabled\n"); if (info_smmu->is_txr_rn_db_pcie_addr == true) IPADBG_LOW("is_txr_rn_db_pcie_addr is PCIE addr\n"); else IPADBG_LOW("is_txr_rn_db_pcie_addr is DDR addr\n"); IPADBG_LOW("LSB 0x%x\n", (u32)info_smmu->transfer_ring_doorbell_pa); IPADBG_LOW("MSB 0x%x\n", (u32)((u64)info_smmu->transfer_ring_doorbell_pa >> 32)); } if (!is_smmu_enabled) { ch_scratch.wdi3.wifi_rp_address_low = (u32)info->transfer_ring_doorbell_pa; Loading Loading @@ -268,6 +377,49 @@ static int ipa3_setup_wdi3_gsi_channel(u8 is_smmu_enabled, (u32)((u64)va >> 32); } } /* * Arch specific: * pcie addr which are not via smmu, use pa directly! * pcie and DDR via 2 different port * assert bit 40 to indicate it is pcie addr * WDI-3.0, MSM --> pcie via smmu * WDI-3.0, MDM --> pcie not via smmu + dual port * assert bit 40 in case */ if (!ipa3_is_msm_device() && is_smmu_enabled) { /* * Ir-respective of smmu enabled don't use IOVA addr * since pcie not via smmu in MDM's */ if (info_smmu->is_txr_rn_db_pcie_addr == true) { ch_scratch.wdi3.wifi_rp_address_low = (u32)info_smmu->transfer_ring_doorbell_pa; ch_scratch.wdi3.wifi_rp_address_high = (u32)((u64)info_smmu->transfer_ring_doorbell_pa >> 32); } } /* * GSI recomendation to set bit-40 for(mdm targets && pcie addr) * from wdi-3.0 interface document */ if (!is_smmu_enabled) { if (!ipa3_is_msm_device() && info->is_txr_rn_db_pcie_addr) ch_scratch.wdi3.wifi_rp_address_high = (u32)((u32)ch_scratch.wdi3.wifi_rp_address_high | (1 << 8)); } else { if (!ipa3_is_msm_device() && info_smmu->is_txr_rn_db_pcie_addr) ch_scratch.wdi3.wifi_rp_address_high = (u32)((u32)ch_scratch.wdi3.wifi_rp_address_high | (1 << 8)); } result = gsi_write_channel_scratch(ep->gsi_chan_hdl, ch_scratch); if (result != GSI_STATUS_SUCCESS) { IPAERR("failed to write evt ring scratch\n"); Loading
include/linux/ipa_wdi3.h +9 −1 Original line number Diff line number Diff line /* Copyright (c) 2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2018-2019, 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 Loading Loading @@ -104,10 +104,12 @@ struct ipa_wdi_reg_intf_in_params { * @transfer_ring_size: size of the transfer ring * @transfer_ring_doorbell_pa: physical address of the doorbell that IPA uC will update the tailpointer of the transfer ring * @is_txr_rn_db_pcie_addr: Bool indicated txr ring DB is pcie or not * @event_ring_base_pa: physical address of the base of the event ring * @event_ring_size: event ring size * @event_ring_doorbell_pa: physical address of the doorbell that IPA uC will update the headpointer of the event ring * @is_evt_rn_db_pcie_addr: Bool indicated evt ring DB is pcie or not * @num_pkt_buffers: Number of pkt buffers allocated. The size of the event ring and the transfer ring has to be atleast ( num_pkt_buffers + 1) * @pkt_offset: packet offset (wdi header length) Loading @@ -120,10 +122,12 @@ struct ipa_wdi_pipe_setup_info { phys_addr_t transfer_ring_base_pa; u32 transfer_ring_size; phys_addr_t transfer_ring_doorbell_pa; bool is_txr_rn_db_pcie_addr; phys_addr_t event_ring_base_pa; u32 event_ring_size; phys_addr_t event_ring_doorbell_pa; bool is_evt_rn_db_pcie_addr; u16 num_pkt_buffers; u16 pkt_offset; Loading @@ -139,10 +143,12 @@ struct ipa_wdi_pipe_setup_info { * @transfer_ring_size: size of the transfer ring * @transfer_ring_doorbell_pa: physical address of the doorbell that IPA uC will update the tailpointer of the transfer ring * @is_txr_rn_db_pcie_addr: Bool indicated txr ring DB is pcie or not * @event_ring_base_pa: physical address of the base of the event ring * @event_ring_size: event ring size * @event_ring_doorbell_pa: physical address of the doorbell that IPA uC will update the headpointer of the event ring * @is_evt_rn_db_pcie_addr: Bool indicated evt ring DB is pcie or not * @num_pkt_buffers: Number of pkt buffers allocated. The size of the event ring and the transfer ring has to be atleast ( num_pkt_buffers + 1) * @pkt_offset: packet offset (wdi header length) Loading @@ -155,10 +161,12 @@ struct ipa_wdi_pipe_setup_info_smmu { struct sg_table transfer_ring_base; u32 transfer_ring_size; phys_addr_t transfer_ring_doorbell_pa; bool is_txr_rn_db_pcie_addr; struct sg_table event_ring_base; u32 event_ring_size; phys_addr_t event_ring_doorbell_pa; bool is_evt_rn_db_pcie_addr; u16 num_pkt_buffers; u16 pkt_offset; Loading