msm: ipa3: add support for SMMU to USB
Add support to IPA USB when IPA SMMU is enabled. IPA USB will create a mapping for USB registers and USB data structures for GSI. CRs-Fixed: 1046497 Change-Id: Ib177606acdfa9b3826c929578d1c8094242f90cd Acked-by: Ady Abraham <adya@qti.qualcomm.com> Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
This commit is contained in:
parent
8b42db2259
commit
072a88c698
3 changed files with 169 additions and 0 deletions
|
@ -162,6 +162,12 @@ struct ipa3_usb_transport_type_ctx {
|
|||
void *user_data;
|
||||
enum ipa3_usb_state state;
|
||||
struct finish_suspend_work_context finish_suspend_work;
|
||||
struct ipa_usb_xdci_chan_params ch_params;
|
||||
};
|
||||
|
||||
struct ipa3_usb_smmu_reg_map {
|
||||
int cnt;
|
||||
phys_addr_t addr;
|
||||
};
|
||||
|
||||
struct ipa3_usb_context {
|
||||
|
@ -179,6 +185,7 @@ struct ipa3_usb_context {
|
|||
ttype_ctx[IPA_USB_TRANSPORT_MAX];
|
||||
struct dentry *dfile_state_info;
|
||||
struct dentry *dent;
|
||||
struct ipa3_usb_smmu_reg_map smmu_reg_map;
|
||||
};
|
||||
|
||||
enum ipa3_usb_op {
|
||||
|
@ -1112,6 +1119,74 @@ static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int ipa3_usb_smmu_map_xdci_channel(
|
||||
struct ipa_usb_xdci_chan_params *params, bool map)
|
||||
{
|
||||
int result;
|
||||
u32 gevntcount_r = rounddown(params->gevntcount_low_addr, PAGE_SIZE);
|
||||
u32 xfer_scratch_r =
|
||||
rounddown(params->xfer_scratch.depcmd_low_addr, PAGE_SIZE);
|
||||
|
||||
if (gevntcount_r != xfer_scratch_r) {
|
||||
IPA_USB_ERR("No support more than 1 page map for USB regs\n");
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (map) {
|
||||
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);
|
||||
if (result) {
|
||||
IPA_USB_ERR("failed to map USB regs %d\n",
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) {
|
||||
IPA_USB_ERR(
|
||||
"No support for map different reg\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
ipa3_usb_ctx->smmu_reg_map.cnt++;
|
||||
} else {
|
||||
if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) {
|
||||
IPA_USB_ERR(
|
||||
"No support for map different reg\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ipa3_usb_ctx->smmu_reg_map.cnt == 1) {
|
||||
result = ipa3_smmu_map_peer_reg(
|
||||
ipa3_usb_ctx->smmu_reg_map.addr, false);
|
||||
if (result) {
|
||||
IPA_USB_ERR("failed to unmap USB regs %d\n",
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
ipa3_usb_ctx->smmu_reg_map.cnt--;
|
||||
}
|
||||
|
||||
result = ipa3_smmu_map_peer_buff(params->xfer_ring_base_addr_iova,
|
||||
params->xfer_ring_base_addr, params->xfer_ring_len, map);
|
||||
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_addr, params->data_buff_base_len, map);
|
||||
if (result) {
|
||||
IPA_USB_ERR("failed to map TRBs buff %d\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipa3_usb_request_xdci_channel(
|
||||
struct ipa_usb_xdci_chan_params *params,
|
||||
struct ipa_req_chan_out_params *out_params)
|
||||
|
@ -1186,6 +1261,16 @@ static int ipa3_usb_request_xdci_channel(
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
result = ipa3_usb_smmu_map_xdci_channel(params, true);
|
||||
if (result) {
|
||||
IPA_USB_ERR("failed to smmu map %d\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* store channel params for SMMU unmap */
|
||||
ipa3_usb_ctx->ttype_ctx[ttype].ch_params = *params;
|
||||
|
||||
chan_params.keep_ipa_awake = params->keep_ipa_awake;
|
||||
chan_params.evt_ring_params.intf = GSI_EVT_CHTYPE_XDCI_EV;
|
||||
chan_params.evt_ring_params.intr = GSI_INTR_IRQ;
|
||||
|
@ -1243,6 +1328,7 @@ static int ipa3_usb_request_xdci_channel(
|
|||
result = ipa3_request_gsi_channel(&chan_params, out_params);
|
||||
if (result) {
|
||||
IPA_USB_ERR("failed to allocate GSI channel\n");
|
||||
ipa3_usb_smmu_map_xdci_channel(params, false);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1273,6 +1359,9 @@ static int ipa3_usb_release_xdci_channel(u32 clnt_hdl,
|
|||
return result;
|
||||
}
|
||||
|
||||
result = ipa3_usb_smmu_map_xdci_channel(
|
||||
&ipa3_usb_ctx->ttype_ctx[ttype].ch_params, false);
|
||||
|
||||
/* Change ipa_usb state to INITIALIZED */
|
||||
if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype))
|
||||
IPA_USB_ERR("failed to change state to initialized\n");
|
||||
|
|
|
@ -1055,6 +1055,83 @@ 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)
|
||||
{
|
||||
struct iommu_domain *smmu_domain;
|
||||
int res;
|
||||
|
||||
if (ipa3_ctx->smmu_s1_bypass)
|
||||
return 0;
|
||||
|
||||
smmu_domain = ipa3_get_smmu_domain();
|
||||
if (!smmu_domain) {
|
||||
IPAERR("invalid smmu domain\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (map) {
|
||||
res = ipa3_iommu_map(smmu_domain, phys_addr, phys_addr,
|
||||
PAGE_SIZE, IOMMU_READ | IOMMU_WRITE | IOMMU_DEVICE);
|
||||
} else {
|
||||
res = iommu_unmap(smmu_domain, phys_addr, PAGE_SIZE);
|
||||
res = (res != PAGE_SIZE);
|
||||
}
|
||||
if (res) {
|
||||
IPAERR("Fail to %s reg 0x%pa\n", map ? "map" : "unmap",
|
||||
&phys_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IPADBG("Peer reg 0x%pa %s\n", &phys_addr, map ? "map" : "unmap");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map)
|
||||
{
|
||||
struct iommu_domain *smmu_domain;
|
||||
int res;
|
||||
|
||||
if (ipa3_ctx->smmu_s1_bypass)
|
||||
return 0;
|
||||
|
||||
smmu_domain = ipa3_get_smmu_domain();
|
||||
if (!smmu_domain) {
|
||||
IPAERR("invalid smmu domain\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (map) {
|
||||
res = ipa3_iommu_map(smmu_domain,
|
||||
rounddown(iova, PAGE_SIZE),
|
||||
rounddown(phys_addr, PAGE_SIZE),
|
||||
roundup(size + iova - rounddown(iova, PAGE_SIZE),
|
||||
PAGE_SIZE),
|
||||
IOMMU_READ | IOMMU_WRITE);
|
||||
if (res) {
|
||||
IPAERR("Fail to map 0x%llx->0x%pa\n", iova, &phys_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
res = iommu_unmap(smmu_domain,
|
||||
rounddown(iova, PAGE_SIZE),
|
||||
roundup(size + iova - rounddown(iova, PAGE_SIZE),
|
||||
PAGE_SIZE));
|
||||
if (res != roundup(size + iova - rounddown(iova, PAGE_SIZE),
|
||||
PAGE_SIZE)) {
|
||||
IPAERR("Fail to unmap 0x%llx->0x%pa\n",
|
||||
iova, &phys_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
IPADBG("Peer buff %s 0x%llx->0x%pa\n", map ? "map" : "unmap",
|
||||
iova, &phys_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params,
|
||||
struct ipa_req_chan_out_params *out_params)
|
||||
{
|
||||
|
|
|
@ -2194,4 +2194,7 @@ 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, phys_addr_t phys_addr,
|
||||
u32 size, bool map);
|
||||
#endif /* _IPA3_I_H_ */
|
||||
|
|
Loading…
Add table
Reference in a new issue