On 8/23/2022 8:55 AM, Stephen Boyd wrote:
Thanks for your time and valuable suggestions!!!
Quoting Srinivasa Rao Mandadapu (2022-08-22 01:22:02)Actually, dev pointer is not available here, hence used pr_err.
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.cWhy can't this be dev_err()?
index b0a63a0..d01c97e 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -333,6 +336,185 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
return 0;
}
+static void adsp_of_unmap_smmu(struct iommu_domain *iommu_dom, const __be32 *prop, int len)
+{
+ unsigned long iova;
+ unsigned int mem_size;
+ int i;
+
+ len /= sizeof(__be32);
+ for (i = 0; i < len; i++) {
+ iova = be32_to_cpu(prop[i++]);
+ /* Skip Physical address*/
+ i++;
+ mem_size = be32_to_cpu(prop[i++]);
+ iommu_unmap(iommu_dom, iova, mem_size);
+ }
+}
+
+static void adsp_rproc_unmap_smmu(struct rproc *rproc, int len)
+{
+ struct fw_rsc_devmem *rsc_fw;
+ struct fw_rsc_hdr *hdr;
+ int offset;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ offset = rproc->table_ptr->offset[i];
+ hdr = (void *)rproc->table_ptr + offset;
+ rsc_fw = (struct fw_rsc_devmem *)hdr + sizeof(*hdr);
+
+ iommu_unmap(rproc->domain, rsc_fw->da, rsc_fw->len);
+ }
+}
+
+static void adsp_unmap_smmu(struct rproc *rproc)
+{
+ struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+ const __be32 *prop;
+ unsigned int len;
+
+ iommu_unmap(adsp->iommu_dom, adsp->mem_phys, adsp->mem_size);
+
+ prop = of_get_property(adsp->dev->of_node, "qcom,adsp-memory-regions", &len);
+ if (prop) {
+ adsp_of_unmap_smmu(adsp->iommu_dom, prop, len);
+ } else {
+ if (rproc->table_ptr)
+ adsp_rproc_unmap_smmu(rproc, rproc->table_ptr->num);
+ }
+
+ iommu_domain_free(adsp->iommu_dom);
+}
+
+static int adsp_of_map_smmu(struct iommu_domain *iommu_dom, const __be32 *prop, int len)
+{
+ unsigned long mem_phys;
+ unsigned long iova;
+ unsigned int mem_size;
+ unsigned int flag;
+ int access_level;
+ int ret;
+ int i;
+
+ len /= sizeof(__be32);
+ for (i = 0; i < len; i++) {
+ iova = be32_to_cpu(prop[i++]);
+ mem_phys = be32_to_cpu(prop[i++]);
+ mem_size = be32_to_cpu(prop[i++]);
+ access_level = be32_to_cpu(prop[i]);
+
+ if (access_level)
+ flag = IOMMU_READ | IOMMU_WRITE;
+ else
+ flag = IOMMU_READ;
+
+ ret = iommu_map(iommu_dom, iova, mem_phys, mem_size, flag);
+ if (ret) {
+ pr_err("failed to map addr = %p mem_size = %x\n", &(mem_phys), mem_size);
Okay. will update.
+ goto of_smmu_unmap;const?
+ }
+ }
+ return 0;
+of_smmu_unmap:
+ adsp_of_unmap_smmu(iommu_dom, prop, i);
+ return ret;
+}
+
+static int adsp_rproc_map_smmu(struct rproc *rproc, int len)
+{
+ struct fw_rsc_devmem *rsc_fw;
Okay. Will update.
+ struct fw_rsc_hdr *hdr;const?
Okay. Will change it.
+ int offset;Why can't this be dev_err()?
+ int ret;
+ int i;
+
+ if (!rproc->table_ptr)
+ return 0;
+
+ for (i = 0; i < rproc->table_ptr->num; i++) {
+ offset = rproc->table_ptr->offset[i];
+ hdr = (void *)rproc->table_ptr + offset;
+ rsc_fw = (struct fw_rsc_devmem *)hdr + sizeof(*hdr);
+
+ ret = iommu_map(rproc->domain, rsc_fw->da, rsc_fw->pa,
+ rsc_fw->len, rsc_fw->flags);
+ if (ret) {
+ pr_err("failed to map addr = %x mem_size = %x\n", rsc_fw->pa, rsc_fw->len);
+ goto rproc_smmu_unmap;Does i need to be incremented? And/or unmap should be done in reverse.
+ }
+ }
+
+ return 0;
+
+rproc_smmu_unmap:
+ adsp_rproc_unmap_smmu(rproc, i);
Here i is the upper bound index in mapping failure case, hence it is used as length. un-mapping is being done from starting till i value.
Please correct me if I am missing some thing.
It seems, if sid is -1 iomap fails, because of alignment issues. Any I will update with return in this case.
+ return ret;Is it a good idea to set the sid to -1? Does that mean all stream IDs?
+}
+
+static int adsp_map_smmu(struct qcom_adsp *adsp, struct rproc *rproc)
+{
+ struct of_phandle_args args;
+ const __be32 *prop;
+ long long sid;
+ unsigned int len;
+ int ret;
+
+ ret = of_parse_phandle_with_args(adsp->dev->of_node, "iommus", "#iommu-cells", 0, &args);
+ if (ret < 0)
+ sid = -1;
It seems not required. Will remove it.
+ elseWhy do we overwrite the error value?
+ sid = args.args[0] & SID_MASK_DEFAULT;
+
+ adsp->iommu_dom = iommu_domain_alloc(adsp->dev->bus);
+ if (!adsp->iommu_dom) {
+ dev_err(adsp->dev, "failed to allocate iommu domain\n");
+ ret = -ENOMEM;
+ goto domain_free;
+ }
+
+ ret = iommu_attach_device(adsp->iommu_dom, adsp->dev);
+ if (ret) {
+ dev_err(adsp->dev, "could not attach device ret = %d\n", ret);
+ ret = -EBUSY;
Actually from HLOS perspective, same IOVA and physical memory is being used. Hence will remove virtual address field in DT.
+ goto detach_device;I find it odd that we're encoding virtual addresses (iovas) into
+ }
+
+ /* Add SID configuration for ADSP Firmware to SMMU */
+ adsp->mem_phys = adsp->mem_phys | (sid << 32);
+
+ ret = iommu_map(adsp->iommu_dom, adsp->mem_phys, adsp->mem_phys,
+ adsp->mem_size, IOMMU_READ | IOMMU_WRITE);
+ if (ret) {
+ dev_err(adsp->dev, "Unable to map ADSP Physical Memory\n");
+ goto sid_unmap;
+ }
+
+ prop = of_get_property(adsp->dev->of_node, "qcom,adsp-memory-regions", &len);
devicetree. Presumably the physical address needs to be in DT as aWill try to carveout the physical addresses and handle it accordingly. If this method is ignored I don't think we need to mention in DT in anyway.
carveout, but after that I would think we're free to allocate the
segments from the carveout however we see fit and then program that into
the SMMU. Maybe DT can be a suggestion, but otherwise can it be ignored?
Yes, it seems it can be ignored. As it is the approach we did for bringing up AudioReach solution, and used when ADSP binary is without metadata section header info.
Will check internally and update accordingly.
Your opinion also helps please!!. Is it okay to keep it as backup option with proper comment, such that this method can be used internally, with raw ADSP binary in early stage bring-up scenarios?
As explained above will remove both of the above methods.
Okay. Will modify the string.
+ if (prop) {Maybe this should be a different string in case it is confused with the
+ ret = adsp_of_map_smmu(adsp->iommu_dom, prop, len);
+ if (ret) {
+ dev_err(adsp->dev, "Unable to map memory regions accessed by ADSP\n");
+ goto sid_unmap;
+ }
+ } else {
+ ret = adsp_rproc_map_smmu(rproc, len);
+ if (ret) {
+ dev_err(adsp->dev, "Unable to map memory regions accessed by ADSP\n");
above print of the same string.
Okay.
+ goto sid_unmap;Newline here please.
+ }
+ }
+ return 0;
+
+sid_unmap:
+ iommu_unmap(adsp->iommu_dom, adsp->mem_phys, adsp->mem_size);
+detach_device:
+ iommu_domain_free(adsp->iommu_dom);
+domain_free:
+ return ret;
+}
+
+
static int adsp_start(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
@@ -343,9 +525,16 @@ static int adsp_start(struct rproc *rproc)
if (ret)
return ret;
+ if (adsp->adsp_sandbox_needed) {
+ ret = adsp_map_smmu(adsp, rproc);
+ if (ret) {
+ dev_err(adsp->dev, "ADSP smmu mapping failed\n");
+ goto disable_irqs;
+ }
+ }
ret = clk_prepare_enable(adsp->xo);
if (ret)
- goto disable_irqs;
+ goto adsp_smmu_unmap;
ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds,
adsp->proxy_pd_count);