Loading Documentation/devicetree/bindings/pci/msm_pcie.txt +13 −2 Original line number Diff line number Diff line Loading @@ -97,7 +97,6 @@ Optional Properties: - iommus: the phandle and stream IDs for the SMMU used by this root complex. This should be used in separate nodes from the main root complex nodes, and is the only property needed in that case. - qcom,smmu-exist: PCIe uses a SMMU. - qcom,smmu-sid-base: The base SMMU SID that PCIe bus driver will use to calculate and assign for each endpoint. - qcom,ep-latency: The time (unit: ms) to wait for the PCIe endpoint to become Loading Loading @@ -141,6 +140,17 @@ Required properties: determined by pci bus topology. Assign the other cells 0 since they are not used. Optional properties: - qcom,iommu-cfg: Determines whether PCIe bus driver is required to configure SMMU that sits behind the PCIe controller. Bit mask: BIT(0) : Indicates if SMMU is present BIT(1) : Set IOMMU attribute S1_BYPASS BIT(2) : Set IOMMU attribute FAST BIT(3) : Set IOMMU attribute ATOMIC BIT(4) : Set IOMMU attribute FORCE COHERENT - qcom,iommu-range: Pair of values describing iova base and size to allocate. Example: pcie0: qcom,pcie@fc520000 { Loading Loading @@ -282,7 +292,6 @@ Example: qcom,msi-gicm-base = <0x160>; qcom,ext-ref-clk; qcom,tlp-rd-size = <0x5>; qcom,smmu-exist; qcom,smmu-sid-base = <0x1480>; qcom,ep-latency = <100>; qcom,switch-latency = <100>; Loading Loading @@ -320,5 +329,7 @@ Example: pcie_rc0: pcie_rc0 { reg = <0x0 0x0 0x0 0x0 0x0>; qcom,iommu-cfg = <0x3> /* SMMU PRESENT. SET S1 BYPASS */ qcom,iommu-range = <0x0 0x10000000 0x0 0x40000000>; }; }; drivers/pci/host/pci-msm.c +170 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <linux/of_pci.h> #include <linux/pci.h> #include <linux/iommu.h> #include <asm/dma-iommu.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <dt-bindings/regulator/qcom,rpmh-regulator.h> Loading Loading @@ -172,6 +173,12 @@ #define GEN2_SPEED 0x2 #define GEN3_SPEED 0x3 #define MSM_PCIE_IOMMU_PRESENT BIT(0) #define MSM_PCIE_IOMMU_S1_BYPASS BIT(1) #define MSM_PCIE_IOMMU_FAST BIT(2) #define MSM_PCIE_IOMMU_ATOMIC BIT(3) #define MSM_PCIE_IOMMU_FORCE_COHERENT BIT(4) #define PHY_READY_TIMEOUT_COUNT 10 #define XMLH_LINK_UP 0x400 #define MAX_LINK_RETRIES 5 Loading Loading @@ -587,7 +594,6 @@ struct msm_pcie_dev_t { bool clk_power_manage_en; bool aux_clk_sync; bool aer_enable; bool smmu_exist; uint32_t smmu_sid_base; uint32_t n_fts; uint32_t max_link_speed; Loading Loading @@ -652,6 +658,9 @@ struct msm_pcie_dev_t { struct msm_root_dev_t { struct msm_pcie_dev_t *pcie_dev; struct pci_dev *pci_dev; uint32_t iommu_cfg; dma_addr_t iommu_base; size_t iommu_size; }; /* debug mask sys interface */ Loading Loading @@ -1250,8 +1259,6 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->msi_gicm_base); PCIE_DBG_FS(dev, "bus_client: %d\n", dev->bus_client); PCIE_DBG_FS(dev, "smmu does %s exist\n", dev->smmu_exist ? "" : "not"); PCIE_DBG_FS(dev, "smmu_sid_base: 0x%x\n", dev->smmu_sid_base); PCIE_DBG_FS(dev, "n_fts: %d\n", Loading Loading @@ -5917,13 +5924,6 @@ static int msm_pcie_probe(struct platform_device *pdev) "AUX clock frequency is %s 19.2MHz.\n", msm_pcie_dev[rc_idx].use_19p2mhz_aux_clk ? "" : "not"); msm_pcie_dev[rc_idx].smmu_exist = of_property_read_bool((&pdev->dev)->of_node, "qcom,smmu-exist"); PCIE_DBG(&msm_pcie_dev[rc_idx], "SMMU does %s exist.\n", msm_pcie_dev[rc_idx].smmu_exist ? "" : "not"); msm_pcie_dev[rc_idx].smmu_sid_base = 0; ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,smmu-sid-base", &msm_pcie_dev[rc_idx].smmu_sid_base); Loading Loading @@ -6338,10 +6338,160 @@ static int msm_pcie_remove(struct platform_device *pdev) return ret; } static int msm_pci_iommu_parse_dt(struct msm_root_dev_t *root_dev) { int ret; struct msm_pcie_dev_t *pcie_dev = root_dev->pcie_dev; struct pci_dev *pci_dev = root_dev->pci_dev; struct device_node *pci_of_node = pci_dev->dev.of_node; ret = of_property_read_u32(pci_of_node, "qcom,iommu-cfg", &root_dev->iommu_cfg); if (ret) { PCIE_DBG(pcie_dev, "PCIe: RC%d: no iommu-cfg present in DT\n", pcie_dev->rc_idx); return 0; } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_S1_BYPASS) { root_dev->iommu_base = 0; root_dev->iommu_size = PAGE_SIZE; } else { u64 iommu_range[2]; ret = of_property_count_elems_of_size(pci_of_node, "qcom,iommu-range", sizeof(iommu_range)); if (ret != 1) { PCIE_ERR(pcie_dev, "invalid entry for iommu address: %d\n", ret); return ret; } ret = of_property_read_u64_array(pci_of_node, "qcom,iommu-range", iommu_range, 2); if (ret) { PCIE_ERR(pcie_dev, "failed to get iommu address: %d\n", ret); return ret; } root_dev->iommu_base = (dma_addr_t)iommu_range[0]; root_dev->iommu_size = (size_t)iommu_range[1]; } PCIE_DBG(pcie_dev, "iommu-cfg: 0x%x iommu-base: %pad iommu-size: 0x%zx\n", root_dev->iommu_cfg, &root_dev->iommu_base, root_dev->iommu_size); return 0; } static int msm_pci_iommu_init(struct msm_root_dev_t *root_dev) { int ret; struct dma_iommu_mapping *mapping; struct msm_pcie_dev_t *pcie_dev = root_dev->pcie_dev; struct pci_dev *pci_dev = root_dev->pci_dev; ret = msm_pci_iommu_parse_dt(root_dev); if (ret) return ret; if (!(root_dev->iommu_cfg & MSM_PCIE_IOMMU_PRESENT)) return 0; mapping = arm_iommu_create_mapping(&pci_bus_type, root_dev->iommu_base, root_dev->iommu_size); if (IS_ERR_OR_NULL(mapping)) { ret = PTR_ERR(mapping); PCIE_ERR(pcie_dev, "PCIe: RC%d: Failed to create IOMMU mapping (%d)\n", pcie_dev->rc_idx, ret); return ret; } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_S1_BYPASS) { int iommu_s1_bypass = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, &iommu_s1_bypass); if (ret) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to set attribute S1_BYPASS: %d\n", pcie_dev->rc_idx, ret); goto release_mapping; } } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_FAST) { int iommu_fast = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_FAST, &iommu_fast); if (ret) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to set attribute FAST: %d\n", pcie_dev->rc_idx, ret); goto release_mapping; } } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_ATOMIC) { int iommu_atomic = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_ATOMIC, &iommu_atomic); if (ret) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to set attribute ATOMIC: %d\n", pcie_dev->rc_idx, ret); goto release_mapping; } } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_FORCE_COHERENT) { int iommu_force_coherent = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT, &iommu_force_coherent); if (ret) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to set attribute FORCE_COHERENT: %d\n", pcie_dev->rc_idx, ret); goto release_mapping; } } ret = arm_iommu_attach_device(&pci_dev->dev, mapping); if (ret) { PCIE_ERR(pcie_dev, "failed to iommu attach device (%d)\n", pcie_dev->rc_idx, ret); goto release_mapping; } PCIE_DBG(pcie_dev, "PCIe: RC%d: successful iommu attach\n", pcie_dev->rc_idx); return 0; release_mapping: arm_iommu_release_mapping(mapping); return ret; } int msm_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *device_id) { int ret; struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(pci_dev->bus); struct msm_root_dev_t *root_dev; Loading @@ -6358,6 +6508,16 @@ int msm_pci_probe(struct pci_dev *pci_dev, root_dev->pci_dev = pci_dev; dev_set_drvdata(&pci_dev->dev, root_dev); ret = msm_pci_iommu_init(root_dev); if (ret) return ret; ret = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(64)); if (ret) { PCIE_ERR(pcie_dev, "DMA set mask failed (%d)\n", ret); return ret; } return 0; } Loading Loading
Documentation/devicetree/bindings/pci/msm_pcie.txt +13 −2 Original line number Diff line number Diff line Loading @@ -97,7 +97,6 @@ Optional Properties: - iommus: the phandle and stream IDs for the SMMU used by this root complex. This should be used in separate nodes from the main root complex nodes, and is the only property needed in that case. - qcom,smmu-exist: PCIe uses a SMMU. - qcom,smmu-sid-base: The base SMMU SID that PCIe bus driver will use to calculate and assign for each endpoint. - qcom,ep-latency: The time (unit: ms) to wait for the PCIe endpoint to become Loading Loading @@ -141,6 +140,17 @@ Required properties: determined by pci bus topology. Assign the other cells 0 since they are not used. Optional properties: - qcom,iommu-cfg: Determines whether PCIe bus driver is required to configure SMMU that sits behind the PCIe controller. Bit mask: BIT(0) : Indicates if SMMU is present BIT(1) : Set IOMMU attribute S1_BYPASS BIT(2) : Set IOMMU attribute FAST BIT(3) : Set IOMMU attribute ATOMIC BIT(4) : Set IOMMU attribute FORCE COHERENT - qcom,iommu-range: Pair of values describing iova base and size to allocate. Example: pcie0: qcom,pcie@fc520000 { Loading Loading @@ -282,7 +292,6 @@ Example: qcom,msi-gicm-base = <0x160>; qcom,ext-ref-clk; qcom,tlp-rd-size = <0x5>; qcom,smmu-exist; qcom,smmu-sid-base = <0x1480>; qcom,ep-latency = <100>; qcom,switch-latency = <100>; Loading Loading @@ -320,5 +329,7 @@ Example: pcie_rc0: pcie_rc0 { reg = <0x0 0x0 0x0 0x0 0x0>; qcom,iommu-cfg = <0x3> /* SMMU PRESENT. SET S1 BYPASS */ qcom,iommu-range = <0x0 0x10000000 0x0 0x40000000>; }; };
drivers/pci/host/pci-msm.c +170 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <linux/of_pci.h> #include <linux/pci.h> #include <linux/iommu.h> #include <asm/dma-iommu.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <dt-bindings/regulator/qcom,rpmh-regulator.h> Loading Loading @@ -172,6 +173,12 @@ #define GEN2_SPEED 0x2 #define GEN3_SPEED 0x3 #define MSM_PCIE_IOMMU_PRESENT BIT(0) #define MSM_PCIE_IOMMU_S1_BYPASS BIT(1) #define MSM_PCIE_IOMMU_FAST BIT(2) #define MSM_PCIE_IOMMU_ATOMIC BIT(3) #define MSM_PCIE_IOMMU_FORCE_COHERENT BIT(4) #define PHY_READY_TIMEOUT_COUNT 10 #define XMLH_LINK_UP 0x400 #define MAX_LINK_RETRIES 5 Loading Loading @@ -587,7 +594,6 @@ struct msm_pcie_dev_t { bool clk_power_manage_en; bool aux_clk_sync; bool aer_enable; bool smmu_exist; uint32_t smmu_sid_base; uint32_t n_fts; uint32_t max_link_speed; Loading Loading @@ -652,6 +658,9 @@ struct msm_pcie_dev_t { struct msm_root_dev_t { struct msm_pcie_dev_t *pcie_dev; struct pci_dev *pci_dev; uint32_t iommu_cfg; dma_addr_t iommu_base; size_t iommu_size; }; /* debug mask sys interface */ Loading Loading @@ -1250,8 +1259,6 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->msi_gicm_base); PCIE_DBG_FS(dev, "bus_client: %d\n", dev->bus_client); PCIE_DBG_FS(dev, "smmu does %s exist\n", dev->smmu_exist ? "" : "not"); PCIE_DBG_FS(dev, "smmu_sid_base: 0x%x\n", dev->smmu_sid_base); PCIE_DBG_FS(dev, "n_fts: %d\n", Loading Loading @@ -5917,13 +5924,6 @@ static int msm_pcie_probe(struct platform_device *pdev) "AUX clock frequency is %s 19.2MHz.\n", msm_pcie_dev[rc_idx].use_19p2mhz_aux_clk ? "" : "not"); msm_pcie_dev[rc_idx].smmu_exist = of_property_read_bool((&pdev->dev)->of_node, "qcom,smmu-exist"); PCIE_DBG(&msm_pcie_dev[rc_idx], "SMMU does %s exist.\n", msm_pcie_dev[rc_idx].smmu_exist ? "" : "not"); msm_pcie_dev[rc_idx].smmu_sid_base = 0; ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,smmu-sid-base", &msm_pcie_dev[rc_idx].smmu_sid_base); Loading Loading @@ -6338,10 +6338,160 @@ static int msm_pcie_remove(struct platform_device *pdev) return ret; } static int msm_pci_iommu_parse_dt(struct msm_root_dev_t *root_dev) { int ret; struct msm_pcie_dev_t *pcie_dev = root_dev->pcie_dev; struct pci_dev *pci_dev = root_dev->pci_dev; struct device_node *pci_of_node = pci_dev->dev.of_node; ret = of_property_read_u32(pci_of_node, "qcom,iommu-cfg", &root_dev->iommu_cfg); if (ret) { PCIE_DBG(pcie_dev, "PCIe: RC%d: no iommu-cfg present in DT\n", pcie_dev->rc_idx); return 0; } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_S1_BYPASS) { root_dev->iommu_base = 0; root_dev->iommu_size = PAGE_SIZE; } else { u64 iommu_range[2]; ret = of_property_count_elems_of_size(pci_of_node, "qcom,iommu-range", sizeof(iommu_range)); if (ret != 1) { PCIE_ERR(pcie_dev, "invalid entry for iommu address: %d\n", ret); return ret; } ret = of_property_read_u64_array(pci_of_node, "qcom,iommu-range", iommu_range, 2); if (ret) { PCIE_ERR(pcie_dev, "failed to get iommu address: %d\n", ret); return ret; } root_dev->iommu_base = (dma_addr_t)iommu_range[0]; root_dev->iommu_size = (size_t)iommu_range[1]; } PCIE_DBG(pcie_dev, "iommu-cfg: 0x%x iommu-base: %pad iommu-size: 0x%zx\n", root_dev->iommu_cfg, &root_dev->iommu_base, root_dev->iommu_size); return 0; } static int msm_pci_iommu_init(struct msm_root_dev_t *root_dev) { int ret; struct dma_iommu_mapping *mapping; struct msm_pcie_dev_t *pcie_dev = root_dev->pcie_dev; struct pci_dev *pci_dev = root_dev->pci_dev; ret = msm_pci_iommu_parse_dt(root_dev); if (ret) return ret; if (!(root_dev->iommu_cfg & MSM_PCIE_IOMMU_PRESENT)) return 0; mapping = arm_iommu_create_mapping(&pci_bus_type, root_dev->iommu_base, root_dev->iommu_size); if (IS_ERR_OR_NULL(mapping)) { ret = PTR_ERR(mapping); PCIE_ERR(pcie_dev, "PCIe: RC%d: Failed to create IOMMU mapping (%d)\n", pcie_dev->rc_idx, ret); return ret; } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_S1_BYPASS) { int iommu_s1_bypass = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, &iommu_s1_bypass); if (ret) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to set attribute S1_BYPASS: %d\n", pcie_dev->rc_idx, ret); goto release_mapping; } } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_FAST) { int iommu_fast = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_FAST, &iommu_fast); if (ret) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to set attribute FAST: %d\n", pcie_dev->rc_idx, ret); goto release_mapping; } } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_ATOMIC) { int iommu_atomic = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_ATOMIC, &iommu_atomic); if (ret) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to set attribute ATOMIC: %d\n", pcie_dev->rc_idx, ret); goto release_mapping; } } if (root_dev->iommu_cfg & MSM_PCIE_IOMMU_FORCE_COHERENT) { int iommu_force_coherent = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT, &iommu_force_coherent); if (ret) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to set attribute FORCE_COHERENT: %d\n", pcie_dev->rc_idx, ret); goto release_mapping; } } ret = arm_iommu_attach_device(&pci_dev->dev, mapping); if (ret) { PCIE_ERR(pcie_dev, "failed to iommu attach device (%d)\n", pcie_dev->rc_idx, ret); goto release_mapping; } PCIE_DBG(pcie_dev, "PCIe: RC%d: successful iommu attach\n", pcie_dev->rc_idx); return 0; release_mapping: arm_iommu_release_mapping(mapping); return ret; } int msm_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *device_id) { int ret; struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(pci_dev->bus); struct msm_root_dev_t *root_dev; Loading @@ -6358,6 +6508,16 @@ int msm_pci_probe(struct pci_dev *pci_dev, root_dev->pci_dev = pci_dev; dev_set_drvdata(&pci_dev->dev, root_dev); ret = msm_pci_iommu_init(root_dev); if (ret) return ret; ret = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(64)); if (ret) { PCIE_ERR(pcie_dev, "DMA set mask failed (%d)\n", ret); return ret; } return 0; } Loading