Loading Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt +16 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,17 @@ Optional property: and follow appropriate steps to ensure communication on the bus can be resumed after subsytem restart. By default slimbus driver register with ADSP subsystem. - qcom,iommu-s1-bypass: Boolean flag to bypass IOMMU stage 1 translation. Optional subnodes: qcom,iommu_slim_ctrl_cb : Child node representing the Slimbus controller context bank. Subnode Required properties: - compatible : Must be "qcom,slim-ctrl-cb"; - iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. Example: slim@fe12f000 { cell-index = <1>; Loading @@ -78,4 +89,9 @@ Example: qcom,rxreg-access; qcom,apps-ch-pipes = <0x60000000>; qcom,ea-pc = <0x30>; iommu_slim_ctrl_cb: qcom,iommu_slim_ctrl_cb { compatible = "qcom,iommu-slim-ctrl-cb"; iommus = <&apps_smmu 0x1 0x0>; }; }; arch/arm64/boot/dts/qcom/sdm845.dtsi +15 −0 Original line number Diff line number Diff line Loading @@ -1810,6 +1810,15 @@ interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,apps-ch-pipes = <0x780000>; qcom,ea-pc = <0x270>; qcom,iommu-s1-bypass; iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb { compatible = "qcom,iommu-slim-ctrl-cb"; iommus = <&apps_smmu 0x1806 0x0>, <&apps_smmu 0x180d 0x0>, <&apps_smmu 0x180e 0x1>, <&apps_smmu 0x1810 0x1>; }; }; slim_qca: slim@17240000 { Loading @@ -1821,6 +1830,12 @@ reg-names = "slimbus_physical", "slimbus_bam_physical"; interrupts = <0 291 0>, <0 292 0>; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,iommu-s1-bypass; iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb { compatible = "qcom,iommu-slim-ctrl-cb"; iommus = <&apps_smmu 0x1813 0x0>; }; /* Slimbus Slave DT for WCN3990 */ btfmslim_codec: wcn3990 { Loading drivers/slimbus/slim-msm-ngd.c +59 −7 Original line number Diff line number Diff line Loading @@ -9,11 +9,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <asm/dma-iommu.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/iommu.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> Loading @@ -23,6 +25,7 @@ #include <linux/clk.h> #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_slimbus.h> #include <linux/timer.h> #include <linux/msm-sps.h> Loading Loading @@ -1665,6 +1668,43 @@ static ssize_t set_mask(struct device *device, struct device_attribute *attr, static DEVICE_ATTR(debug_mask, 0644, show_mask, set_mask); static const struct of_device_id ngd_slim_dt_match[] = { { .compatible = "qcom,slim-ngd", }, { .compatible = "qcom,iommu-slim-ctrl-cb", }, {} }; static int ngd_slim_iommu_probe(struct device *dev) { struct platform_device *pdev; struct msm_slim_ctrl *ctrl_dev; if (unlikely(!dev->parent)) { dev_err(dev, "%s no parent for this device\n", __func__); return -EINVAL; } pdev = to_platform_device(dev->parent); if (!pdev) { dev_err(dev, "%s Parent platform device not found\n", __func__); return -EINVAL; } ctrl_dev = platform_get_drvdata(pdev); if (!ctrl_dev) { dev_err(dev, "%s NULL controller device\n", __func__); return -EINVAL; } ctrl_dev->iommu_desc.cb_dev = dev; SLIM_INFO(ctrl_dev, "NGD IOMMU initialization complete\n"); return 0; } static int ngd_slim_probe(struct platform_device *pdev) { struct msm_slim_ctrl *dev; Loading @@ -1676,6 +1716,10 @@ static int ngd_slim_probe(struct platform_device *pdev) bool slim_mdm = false; const char *ext_modem_id = NULL; if (of_device_is_compatible(pdev->dev.of_node, "qcom,iommu-slim-ctrl-cb")) return ngd_slim_iommu_probe(&pdev->dev); slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "slimbus_physical"); if (!slim_mem) { Loading Loading @@ -1774,6 +1818,17 @@ static int ngd_slim_probe(struct platform_device *pdev) "qcom,slim-mdm", &ext_modem_id); if (!ret) slim_mdm = true; dev->iommu_desc.s1_bypass = of_property_read_bool( pdev->dev.of_node, "qcom,iommu-s1-bypass"); ret = of_platform_populate(pdev->dev.of_node, ngd_slim_dt_match, NULL, &pdev->dev); if (ret) { dev_err(dev->dev, "%s: Failed to of_platform_populate %d\n", __func__, ret); goto err_ctrl_failed; } } else { dev->ctrl.nr = pdev->id; } Loading Loading @@ -1920,6 +1975,10 @@ static int ngd_slim_remove(struct platform_device *pdev) struct msm_slim_ctrl *dev = platform_get_drvdata(pdev); ngd_slim_enable(dev, false); if (!IS_ERR_OR_NULL(dev->iommu_desc.iommu_map)) { arm_iommu_detach_device(dev->iommu_desc.cb_dev); arm_iommu_release_mapping(dev->iommu_desc.iommu_map); } if (dev->sysfs_created) sysfs_remove_file(&dev->dev->kobj, &dev_attr_debug_mask.attr); Loading Loading @@ -2091,13 +2150,6 @@ static const struct dev_pm_ops ngd_slim_dev_pm_ops = { ) }; static const struct of_device_id ngd_slim_dt_match[] = { { .compatible = "qcom,slim-ngd", }, {} }; static struct platform_driver ngd_slim_driver = { .probe = ngd_slim_probe, .remove = ngd_slim_remove, Loading drivers/slimbus/slim-msm.c +103 −8 Original line number Diff line number Diff line Loading @@ -9,17 +9,21 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/pm_runtime.h> #include <linux/dma-mapping.h> #include <asm/dma-iommu.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/gcd.h> #include <linux/msm-sps.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/slimbus/slimbus.h> #include <linux/msm-sps.h> #include <linux/gcd.h> #include "slim-msm.h" /* Pipe Number Offset Mask */ #define P_OFF_MASK 0x3FC #define MSM_SLIM_VA_START (0x40000000) #define MSM_SLIM_VA_SIZE (0xC0000000) int msm_slim_rx_enqueue(struct msm_slim_ctrl *dev, u32 *buf, u8 len) { Loading Loading @@ -164,17 +168,61 @@ void msm_slim_free_endpoint(struct msm_slim_endp *ep) ep->sps = NULL; } static int msm_slim_iommu_attach(struct msm_slim_ctrl *ctrl_dev) { struct dma_iommu_mapping *iommu_map; dma_addr_t va_start = MSM_SLIM_VA_START; size_t va_size = MSM_SLIM_VA_SIZE; int bypass = 1; struct device *dev; if (unlikely(!ctrl_dev)) return -EINVAL; if (!ctrl_dev->iommu_desc.cb_dev) return 0; dev = ctrl_dev->iommu_desc.cb_dev; iommu_map = arm_iommu_create_mapping(&platform_bus_type, va_start, va_size); if (IS_ERR(iommu_map)) { dev_err(dev, "%s iommu_create_mapping failure\n", __func__); return PTR_ERR(iommu_map); } if (ctrl_dev->iommu_desc.s1_bypass) { if (iommu_domain_set_attr(iommu_map->domain, DOMAIN_ATTR_S1_BYPASS, &bypass)) { dev_err(dev, "%s Can't bypass s1 translation\n", __func__); arm_iommu_release_mapping(iommu_map); return -EIO; } } if (arm_iommu_attach_device(dev, iommu_map)) { dev_err(dev, "%s can't arm_iommu_attach_device\n", __func__); arm_iommu_release_mapping(iommu_map); return -EIO; } ctrl_dev->iommu_desc.iommu_map = iommu_map; SLIM_INFO(ctrl_dev, "NGD IOMMU Attach complete\n"); return 0; } int msm_slim_sps_mem_alloc( struct msm_slim_ctrl *dev, struct sps_mem_buffer *mem, u32 len) { dma_addr_t phys; struct device *dma_dev = dev->iommu_desc.cb_dev ? dev->iommu_desc.cb_dev : dev->dev; mem->size = len; mem->min_size = 0; mem->base = dma_alloc_coherent(dev->dev, mem->size, &phys, GFP_KERNEL); mem->base = dma_alloc_coherent(dma_dev, mem->size, &phys, GFP_KERNEL); if (!mem->base) { dev_err(dev->dev, "dma_alloc_coherent(%d) failed\n", len); dev_err(dma_dev, "dma_alloc_coherent(%d) failed\n", len); return -ENOMEM; } Loading Loading @@ -387,6 +435,10 @@ int msm_alloc_port(struct slim_controller *ctrl, u8 pn) if (pn >= dev->port_nums) return -ENODEV; ret = msm_slim_iommu_attach(dev); if (ret) return ret; endpoint = &dev->pipes[pn]; ret = msm_slim_init_endpoint(dev, endpoint); dev_dbg(dev->dev, "sps register bam error code:%x\n", ret); Loading Loading @@ -435,9 +487,37 @@ enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr, return SLIM_P_INPROGRESS; } static void msm_slim_port_cb(struct sps_event_notify *ev) static int msm_slim_iommu_map(struct msm_slim_ctrl *dev, phys_addr_t iobuf, u32 len) { int ret; if (!dev->iommu_desc.cb_dev) return 0; ret = iommu_map(dev->iommu_desc.iommu_map->domain, rounddown(iobuf, PAGE_SIZE), rounddown(iobuf, PAGE_SIZE), roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))), PAGE_SIZE), IOMMU_READ | IOMMU_WRITE); return ret; } static void msm_slim_iommu_unmap(struct msm_slim_ctrl *dev, phys_addr_t iobuf, u32 len) { if (!dev->iommu_desc.cb_dev) return; iommu_unmap(dev->iommu_desc.iommu_map->domain, rounddown(iobuf, PAGE_SIZE), roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))), PAGE_SIZE)); } static void msm_slim_port_cb(struct sps_event_notify *ev) { struct msm_slim_ctrl *dev = ev->user; struct completion *comp = ev->data.transfer.user; struct sps_iovec *iovec = &ev->data.transfer.iovec; Loading @@ -450,6 +530,8 @@ static void msm_slim_port_cb(struct sps_event_notify *ev) pr_err("%s: ERR event %d\n", __func__, ev->event_id); } if (dev) msm_slim_iommu_unmap(dev, iovec->addr, iovec->size); if (comp) complete(comp); } Loading @@ -467,14 +549,19 @@ int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf, if (!dev->pipes[pn].connected) return -ENOTCONN; ret = msm_slim_iommu_map(dev, iobuf, len); if (ret) return ret; sreg.options = (SPS_EVENT_DESC_DONE|SPS_EVENT_ERROR); sreg.mode = SPS_TRIGGER_WAIT; sreg.xfer_done = NULL; sreg.callback = msm_slim_port_cb; sreg.user = NULL; sreg.user = dev; ret = sps_register_event(dev->pipes[pn].sps, &sreg); if (ret) { dev_dbg(dev->dev, "sps register event error:%x\n", ret); msm_slim_iommu_unmap(dev, iobuf, len); return ret; } ret = sps_transfer_one(dev->pipes[pn].sps, iobuf, len, comp, Loading @@ -490,6 +577,8 @@ int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf, PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver)); /* Make sure that port registers are updated before returning */ mb(); } else { msm_slim_iommu_unmap(dev, iobuf, len); } return ret; Loading Loading @@ -1102,6 +1191,12 @@ int msm_slim_sps_init(struct msm_slim_ctrl *dev, struct resource *bam_mem, } init_msgq: ret = msm_slim_iommu_attach(dev); if (ret) { sps_deregister_bam_device(bam_handle); return ret; } ret = msm_slim_init_rx_msgq(dev, pipe_reg); if (ret) dev_err(dev->dev, "msm_slim_init_rx_msgq failed 0x%x\n", ret); Loading drivers/slimbus/slim-msm.h +8 −1 Original line number Diff line number Diff line /* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2011-2017, 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 @@ -263,10 +263,17 @@ struct msm_slim_bulk_wr { bool in_progress; }; struct msm_slim_iommu { struct device *cb_dev; struct dma_iommu_mapping *iommu_map; bool s1_bypass; }; struct msm_slim_ctrl { struct slim_controller ctrl; struct slim_framer framer; struct device *dev; struct msm_slim_iommu iommu_desc; void __iomem *base; struct resource *slew_mem; struct resource *bam_mem; Loading Loading
Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt +16 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,17 @@ Optional property: and follow appropriate steps to ensure communication on the bus can be resumed after subsytem restart. By default slimbus driver register with ADSP subsystem. - qcom,iommu-s1-bypass: Boolean flag to bypass IOMMU stage 1 translation. Optional subnodes: qcom,iommu_slim_ctrl_cb : Child node representing the Slimbus controller context bank. Subnode Required properties: - compatible : Must be "qcom,slim-ctrl-cb"; - iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. Example: slim@fe12f000 { cell-index = <1>; Loading @@ -78,4 +89,9 @@ Example: qcom,rxreg-access; qcom,apps-ch-pipes = <0x60000000>; qcom,ea-pc = <0x30>; iommu_slim_ctrl_cb: qcom,iommu_slim_ctrl_cb { compatible = "qcom,iommu-slim-ctrl-cb"; iommus = <&apps_smmu 0x1 0x0>; }; };
arch/arm64/boot/dts/qcom/sdm845.dtsi +15 −0 Original line number Diff line number Diff line Loading @@ -1810,6 +1810,15 @@ interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,apps-ch-pipes = <0x780000>; qcom,ea-pc = <0x270>; qcom,iommu-s1-bypass; iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb { compatible = "qcom,iommu-slim-ctrl-cb"; iommus = <&apps_smmu 0x1806 0x0>, <&apps_smmu 0x180d 0x0>, <&apps_smmu 0x180e 0x1>, <&apps_smmu 0x1810 0x1>; }; }; slim_qca: slim@17240000 { Loading @@ -1821,6 +1830,12 @@ reg-names = "slimbus_physical", "slimbus_bam_physical"; interrupts = <0 291 0>, <0 292 0>; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,iommu-s1-bypass; iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb { compatible = "qcom,iommu-slim-ctrl-cb"; iommus = <&apps_smmu 0x1813 0x0>; }; /* Slimbus Slave DT for WCN3990 */ btfmslim_codec: wcn3990 { Loading
drivers/slimbus/slim-msm-ngd.c +59 −7 Original line number Diff line number Diff line Loading @@ -9,11 +9,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <asm/dma-iommu.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/iommu.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> Loading @@ -23,6 +25,7 @@ #include <linux/clk.h> #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_slimbus.h> #include <linux/timer.h> #include <linux/msm-sps.h> Loading Loading @@ -1665,6 +1668,43 @@ static ssize_t set_mask(struct device *device, struct device_attribute *attr, static DEVICE_ATTR(debug_mask, 0644, show_mask, set_mask); static const struct of_device_id ngd_slim_dt_match[] = { { .compatible = "qcom,slim-ngd", }, { .compatible = "qcom,iommu-slim-ctrl-cb", }, {} }; static int ngd_slim_iommu_probe(struct device *dev) { struct platform_device *pdev; struct msm_slim_ctrl *ctrl_dev; if (unlikely(!dev->parent)) { dev_err(dev, "%s no parent for this device\n", __func__); return -EINVAL; } pdev = to_platform_device(dev->parent); if (!pdev) { dev_err(dev, "%s Parent platform device not found\n", __func__); return -EINVAL; } ctrl_dev = platform_get_drvdata(pdev); if (!ctrl_dev) { dev_err(dev, "%s NULL controller device\n", __func__); return -EINVAL; } ctrl_dev->iommu_desc.cb_dev = dev; SLIM_INFO(ctrl_dev, "NGD IOMMU initialization complete\n"); return 0; } static int ngd_slim_probe(struct platform_device *pdev) { struct msm_slim_ctrl *dev; Loading @@ -1676,6 +1716,10 @@ static int ngd_slim_probe(struct platform_device *pdev) bool slim_mdm = false; const char *ext_modem_id = NULL; if (of_device_is_compatible(pdev->dev.of_node, "qcom,iommu-slim-ctrl-cb")) return ngd_slim_iommu_probe(&pdev->dev); slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "slimbus_physical"); if (!slim_mem) { Loading Loading @@ -1774,6 +1818,17 @@ static int ngd_slim_probe(struct platform_device *pdev) "qcom,slim-mdm", &ext_modem_id); if (!ret) slim_mdm = true; dev->iommu_desc.s1_bypass = of_property_read_bool( pdev->dev.of_node, "qcom,iommu-s1-bypass"); ret = of_platform_populate(pdev->dev.of_node, ngd_slim_dt_match, NULL, &pdev->dev); if (ret) { dev_err(dev->dev, "%s: Failed to of_platform_populate %d\n", __func__, ret); goto err_ctrl_failed; } } else { dev->ctrl.nr = pdev->id; } Loading Loading @@ -1920,6 +1975,10 @@ static int ngd_slim_remove(struct platform_device *pdev) struct msm_slim_ctrl *dev = platform_get_drvdata(pdev); ngd_slim_enable(dev, false); if (!IS_ERR_OR_NULL(dev->iommu_desc.iommu_map)) { arm_iommu_detach_device(dev->iommu_desc.cb_dev); arm_iommu_release_mapping(dev->iommu_desc.iommu_map); } if (dev->sysfs_created) sysfs_remove_file(&dev->dev->kobj, &dev_attr_debug_mask.attr); Loading Loading @@ -2091,13 +2150,6 @@ static const struct dev_pm_ops ngd_slim_dev_pm_ops = { ) }; static const struct of_device_id ngd_slim_dt_match[] = { { .compatible = "qcom,slim-ngd", }, {} }; static struct platform_driver ngd_slim_driver = { .probe = ngd_slim_probe, .remove = ngd_slim_remove, Loading
drivers/slimbus/slim-msm.c +103 −8 Original line number Diff line number Diff line Loading @@ -9,17 +9,21 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/pm_runtime.h> #include <linux/dma-mapping.h> #include <asm/dma-iommu.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/gcd.h> #include <linux/msm-sps.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/slimbus/slimbus.h> #include <linux/msm-sps.h> #include <linux/gcd.h> #include "slim-msm.h" /* Pipe Number Offset Mask */ #define P_OFF_MASK 0x3FC #define MSM_SLIM_VA_START (0x40000000) #define MSM_SLIM_VA_SIZE (0xC0000000) int msm_slim_rx_enqueue(struct msm_slim_ctrl *dev, u32 *buf, u8 len) { Loading Loading @@ -164,17 +168,61 @@ void msm_slim_free_endpoint(struct msm_slim_endp *ep) ep->sps = NULL; } static int msm_slim_iommu_attach(struct msm_slim_ctrl *ctrl_dev) { struct dma_iommu_mapping *iommu_map; dma_addr_t va_start = MSM_SLIM_VA_START; size_t va_size = MSM_SLIM_VA_SIZE; int bypass = 1; struct device *dev; if (unlikely(!ctrl_dev)) return -EINVAL; if (!ctrl_dev->iommu_desc.cb_dev) return 0; dev = ctrl_dev->iommu_desc.cb_dev; iommu_map = arm_iommu_create_mapping(&platform_bus_type, va_start, va_size); if (IS_ERR(iommu_map)) { dev_err(dev, "%s iommu_create_mapping failure\n", __func__); return PTR_ERR(iommu_map); } if (ctrl_dev->iommu_desc.s1_bypass) { if (iommu_domain_set_attr(iommu_map->domain, DOMAIN_ATTR_S1_BYPASS, &bypass)) { dev_err(dev, "%s Can't bypass s1 translation\n", __func__); arm_iommu_release_mapping(iommu_map); return -EIO; } } if (arm_iommu_attach_device(dev, iommu_map)) { dev_err(dev, "%s can't arm_iommu_attach_device\n", __func__); arm_iommu_release_mapping(iommu_map); return -EIO; } ctrl_dev->iommu_desc.iommu_map = iommu_map; SLIM_INFO(ctrl_dev, "NGD IOMMU Attach complete\n"); return 0; } int msm_slim_sps_mem_alloc( struct msm_slim_ctrl *dev, struct sps_mem_buffer *mem, u32 len) { dma_addr_t phys; struct device *dma_dev = dev->iommu_desc.cb_dev ? dev->iommu_desc.cb_dev : dev->dev; mem->size = len; mem->min_size = 0; mem->base = dma_alloc_coherent(dev->dev, mem->size, &phys, GFP_KERNEL); mem->base = dma_alloc_coherent(dma_dev, mem->size, &phys, GFP_KERNEL); if (!mem->base) { dev_err(dev->dev, "dma_alloc_coherent(%d) failed\n", len); dev_err(dma_dev, "dma_alloc_coherent(%d) failed\n", len); return -ENOMEM; } Loading Loading @@ -387,6 +435,10 @@ int msm_alloc_port(struct slim_controller *ctrl, u8 pn) if (pn >= dev->port_nums) return -ENODEV; ret = msm_slim_iommu_attach(dev); if (ret) return ret; endpoint = &dev->pipes[pn]; ret = msm_slim_init_endpoint(dev, endpoint); dev_dbg(dev->dev, "sps register bam error code:%x\n", ret); Loading Loading @@ -435,9 +487,37 @@ enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr, return SLIM_P_INPROGRESS; } static void msm_slim_port_cb(struct sps_event_notify *ev) static int msm_slim_iommu_map(struct msm_slim_ctrl *dev, phys_addr_t iobuf, u32 len) { int ret; if (!dev->iommu_desc.cb_dev) return 0; ret = iommu_map(dev->iommu_desc.iommu_map->domain, rounddown(iobuf, PAGE_SIZE), rounddown(iobuf, PAGE_SIZE), roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))), PAGE_SIZE), IOMMU_READ | IOMMU_WRITE); return ret; } static void msm_slim_iommu_unmap(struct msm_slim_ctrl *dev, phys_addr_t iobuf, u32 len) { if (!dev->iommu_desc.cb_dev) return; iommu_unmap(dev->iommu_desc.iommu_map->domain, rounddown(iobuf, PAGE_SIZE), roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))), PAGE_SIZE)); } static void msm_slim_port_cb(struct sps_event_notify *ev) { struct msm_slim_ctrl *dev = ev->user; struct completion *comp = ev->data.transfer.user; struct sps_iovec *iovec = &ev->data.transfer.iovec; Loading @@ -450,6 +530,8 @@ static void msm_slim_port_cb(struct sps_event_notify *ev) pr_err("%s: ERR event %d\n", __func__, ev->event_id); } if (dev) msm_slim_iommu_unmap(dev, iovec->addr, iovec->size); if (comp) complete(comp); } Loading @@ -467,14 +549,19 @@ int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf, if (!dev->pipes[pn].connected) return -ENOTCONN; ret = msm_slim_iommu_map(dev, iobuf, len); if (ret) return ret; sreg.options = (SPS_EVENT_DESC_DONE|SPS_EVENT_ERROR); sreg.mode = SPS_TRIGGER_WAIT; sreg.xfer_done = NULL; sreg.callback = msm_slim_port_cb; sreg.user = NULL; sreg.user = dev; ret = sps_register_event(dev->pipes[pn].sps, &sreg); if (ret) { dev_dbg(dev->dev, "sps register event error:%x\n", ret); msm_slim_iommu_unmap(dev, iobuf, len); return ret; } ret = sps_transfer_one(dev->pipes[pn].sps, iobuf, len, comp, Loading @@ -490,6 +577,8 @@ int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf, PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver)); /* Make sure that port registers are updated before returning */ mb(); } else { msm_slim_iommu_unmap(dev, iobuf, len); } return ret; Loading Loading @@ -1102,6 +1191,12 @@ int msm_slim_sps_init(struct msm_slim_ctrl *dev, struct resource *bam_mem, } init_msgq: ret = msm_slim_iommu_attach(dev); if (ret) { sps_deregister_bam_device(bam_handle); return ret; } ret = msm_slim_init_rx_msgq(dev, pipe_reg); if (ret) dev_err(dev->dev, "msm_slim_init_rx_msgq failed 0x%x\n", ret); Loading
drivers/slimbus/slim-msm.h +8 −1 Original line number Diff line number Diff line /* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2011-2017, 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 @@ -263,10 +263,17 @@ struct msm_slim_bulk_wr { bool in_progress; }; struct msm_slim_iommu { struct device *cb_dev; struct dma_iommu_mapping *iommu_map; bool s1_bypass; }; struct msm_slim_ctrl { struct slim_controller ctrl; struct slim_framer framer; struct device *dev; struct msm_slim_iommu iommu_desc; void __iomem *base; struct resource *slew_mem; struct resource *bam_mem; Loading