Loading Documentation/devicetree/bindings/dma/qcom_gpi.txt +25 −8 Original line number Diff line number Diff line Loading @@ -12,13 +12,12 @@ Main node properties: - #dma-cells Usage: required Value type: <u32> Definition: Number of parameters client will provide. Must be set to 6. 1st parameter: gpii index 2nd parameter: channel index 3rd parameter: serial engine index 4th parameter: bus protocol, 1 for SPI, 2 for UART, 3 for I2C 5th parameter: channel ring length in transfer ring elements 6th parameter: event processing priority, set to 0 for lowest latency Definition: Number of parameters client will provide. Must be set to 5. 1st parameter: channel index, 0 for TX, 1 for RX 2nd parameter: serial engine index 3rd parameter: bus protocol, 1 for SPI, 2 for UART, 3 for I2C 4th parameter: channel ring length in transfer ring elements 5th parameter: event processing priority, set to 0 for lowest latency - compatible Usage: required Loading Loading @@ -64,11 +63,27 @@ Main node properties: for the controller. For more detail please check binding documentation arm,smmu.txt - qcom,smmu-cfg Usage: required Value type: <u32> Definition: Determine whether GPI driver require to configure SMMU that sits behind GPI controller. Bit mask: BIT(0) : Attach address mapping to endpoint device BIT(1) : Set SMMU attribute S1_BYPASS BIT(2) : Set SMMU attribute FAST BIT(3) : Set SMMU attribute ATOMIC - qcom,iova-range Usage: required if SMMU S1 translation is enabled Value type: Array of <u64> Definition: Pair of values describing iova base and size to allocate. ======== Example: ======== gpi_dma0: qcom,gpi-dma@0x800000 { #dma-cells = <6>; #dma-cells = <5>; compatible = "qcom,gpi-dma"; reg = <0x800000 0x60000>; reg-names = "gpi-top"; Loading @@ -80,5 +95,7 @@ gpi_dma0: qcom,gpi-dma@0x800000 { qcom,gpii-mask = <0xfa>; qcom,ev-factor = <2>; iommus = <&apps_smmu 0x0016 0x0>; qcom,smmu-cfg = <0x1> qcom,iova-range = <0x0 0x100000 0x0 0x100000>; status = "ok"; }; arch/arm64/boot/dts/qcom/sdm845.dtsi +6 −2 Original line number Diff line number Diff line Loading @@ -3558,7 +3558,7 @@ }; gpi_dma0: qcom,gpi-dma@0x800000 { #dma-cells = <6>; #dma-cells = <5>; compatible = "qcom,gpi-dma"; reg = <0x800000 0x60000>; reg-names = "gpi-top"; Loading @@ -3570,11 +3570,13 @@ qcom,gpii-mask = <0xfa>; qcom,ev-factor = <2>; iommus = <&apps_smmu 0x0016 0x0>; qcom,smmu-cfg = <0x1>; qcom,iova-range = <0x0 0x100000 0x0 0x100000>; status = "ok"; }; gpi_dma1: qcom,gpi-dma@0xa00000 { #dma-cells = <6>; #dma-cells = <5>; compatible = "qcom,gpi-dma"; reg = <0xa00000 0x60000>; reg-names = "gpi-top"; Loading @@ -3586,6 +3588,8 @@ qcom,gpii-mask = <0xfa>; qcom,ev-factor = <2>; iommus = <&apps_smmu 0x06d6 0x0>; qcom,smmu-cfg = <0x1>; qcom,iova-range = <0x0 0x100000 0x0 0x100000>; status = "ok"; }; Loading drivers/dma/qcom/gpi.c +205 −45 Original line number Diff line number Diff line Loading @@ -131,9 +131,11 @@ enum EV_PRIORITY { #define GPI_LABEL_SIZE (256) #define GPI_DBG_COMMON (99) #define MAX_CHANNELS_PER_GPII (2) #define GPI_TX_CHAN (0) #define GPI_RX_CHAN (1) #define CMD_TIMEOUT_MS (50) #define STATE_IGNORE (U32_MAX) #define REQ_OF_DMA_ARGS (6) /* # of arguments required from client */ #define REQ_OF_DMA_ARGS (5) /* # of arguments required from client */ struct __packed gpi_error_log_entry { u32 routine : 4; Loading Loading @@ -437,6 +439,9 @@ struct gpi_dev { u32 max_gpii; /* maximum # of gpii instances available per gpi block */ u32 gpii_mask; /* gpii instances available for apps */ u32 ev_factor; /* ev ring length factor */ u32 smmu_cfg; dma_addr_t iova_base; size_t iova_size; struct gpii *gpiis; void *ilctxt; u32 ipc_log_lvl; Loading Loading @@ -509,6 +514,11 @@ struct gpi_desc { struct gpii_chan *gpii_chan; }; #define GPI_SMMU_ATTACH BIT(0) #define GPI_SMMU_S1_BYPASS BIT(1) #define GPI_SMMU_FAST BIT(2) #define GPI_SMMU_ATOMIC BIT(3) const u32 GPII_CHAN_DIR[MAX_CHANNELS_PER_GPII] = { GPI_CHTYPE_DIR_OUT, GPI_CHTYPE_DIR_IN }; Loading Loading @@ -2464,12 +2474,53 @@ static int gpi_alloc_chan_resources(struct dma_chan *chan) return ret; } static int gpi_find_avail_gpii(struct gpi_dev *gpi_dev, u32 seid) { int gpii; struct gpii_chan *tx_chan, *rx_chan; /* check if same seid is already configured for another chid */ for (gpii = 0; gpii < gpi_dev->max_gpii; gpii++) { if (!((1 << gpii) & gpi_dev->gpii_mask)) continue; tx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_TX_CHAN]; rx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_RX_CHAN]; if (rx_chan->vc.chan.client_count && rx_chan->seid == seid) return gpii; if (tx_chan->vc.chan.client_count && tx_chan->seid == seid) return gpii; } /* no channels configured with same seid, return next avail gpii */ for (gpii = 0; gpii < gpi_dev->max_gpii; gpii++) { if (!((1 << gpii) & gpi_dev->gpii_mask)) continue; tx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_TX_CHAN]; rx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_RX_CHAN]; /* check if gpii is configured */ if (tx_chan->vc.chan.client_count || rx_chan->vc.chan.client_count) continue; /* found a free gpii */ return gpii; } /* no gpii instance available to use */ return -EIO; } /* gpi_of_dma_xlate: open client requested channel */ static struct dma_chan *gpi_of_dma_xlate(struct of_phandle_args *args, struct of_dma *of_dma) { struct gpi_dev *gpi_dev = (struct gpi_dev *)of_dma->of_dma_data; u32 gpii, chid; u32 seid, chid; int gpii; struct gpii_chan *gpii_chan; if (args->args_count < REQ_OF_DMA_ARGS) { Loading @@ -2479,25 +2530,33 @@ static struct dma_chan *gpi_of_dma_xlate(struct of_phandle_args *args, return NULL; } /* Check if valid gpii instance */ gpii = args->args[0]; if (!((1 << gpii) & gpi_dev->gpii_mask)) { GPI_ERR(gpi_dev, "gpii instance:%d is not supported\n", gpii); chid = args->args[0]; if (chid >= MAX_CHANNELS_PER_GPII) { GPI_ERR(gpi_dev, "gpii channel:%d not valid\n", chid); return NULL; } chid = args->args[1]; if (chid >= MAX_CHANNELS_PER_GPII) { GPI_ERR(gpi_dev, "gpii channel:%d not valid\n", chid); seid = args->args[1]; /* find next available gpii to use */ gpii = gpi_find_avail_gpii(gpi_dev, seid); if (gpii < 0) { GPI_ERR(gpi_dev, "no available gpii instances\n"); return NULL; } /* get ring size, protocol, se_id, and priority */ gpii_chan = &gpi_dev->gpiis[gpii].gpii_chan[chid]; gpii_chan->seid = args->args[2]; gpii_chan->protocol = args->args[3]; gpii_chan->req_tres = args->args[4]; gpii_chan->priority = args->args[5]; if (gpii_chan->vc.chan.client_count) { GPI_ERR(gpi_dev, "gpii:%d chid:%d seid:%d already configured\n", gpii, chid, gpii_chan->seid); return NULL; } /* get ring size, protocol, se_id, and priority */ gpii_chan->seid = seid; gpii_chan->protocol = args->args[2]; gpii_chan->req_tres = args->args[3]; gpii_chan->priority = args->args[4]; GPI_LOG(gpi_dev, "client req. gpii:%u chid:%u #_tre:%u priority:%u protocol:%u\n", Loading Loading @@ -2562,52 +2621,123 @@ static void gpi_setup_debug(struct gpi_dev *gpi_dev) } } static struct dma_iommu_mapping *gpi_create_mapping(struct gpi_dev *gpi_dev) { dma_addr_t base; size_t size; /* * If S1_BYPASS enabled then iommu space is not used, however framework * still require clients to create a mapping space before attaching. So * set to smallest size required by iommu framework. */ if (gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS) { base = 0; size = PAGE_SIZE; } else { base = gpi_dev->iova_base; size = gpi_dev->iova_size; } GPI_LOG(gpi_dev, "Creating iommu mapping of base:0x%llx size:%lu\n", base, size); return arm_iommu_create_mapping(&platform_bus_type, base, size); } static int gpi_dma_mask(struct gpi_dev *gpi_dev) { int mask = 64; if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) { unsigned long addr; addr = gpi_dev->iova_base + gpi_dev->iova_size + 1; mask = find_last_bit(&addr, 64); } GPI_LOG(gpi_dev, "Setting dma mask to %d\n", mask); return dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(mask)); } static int gpi_smmu_init(struct gpi_dev *gpi_dev) { u64 size = PAGE_SIZE; dma_addr_t base = 0x0; struct dma_iommu_mapping *map; int attr, ret; struct dma_iommu_mapping *mapping = NULL; int ret; map = arm_iommu_create_mapping(&platform_bus_type, base, size); if (IS_ERR_OR_NULL(map)) { ret = PTR_ERR(map) ? : -EIO; GPI_ERR(gpi_dev, "error create_mapping, ret:%d\n", ret); return ret; if (gpi_dev->smmu_cfg) { /* create mapping table */ mapping = gpi_create_mapping(gpi_dev); if (IS_ERR(mapping)) { GPI_ERR(gpi_dev, "Failed to create iommu mapping, ret:%ld\n", PTR_ERR(mapping)); return PTR_ERR(mapping); } if (gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS) { int s1_bypass = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, &s1_bypass); if (ret) { GPI_ERR(gpi_dev, "Failed to set attr S1_BYPASS, ret:%d\n", ret); goto release_mapping; } } if (gpi_dev->smmu_cfg & GPI_SMMU_FAST) { int fast = 1; attr = 1; ret = iommu_domain_set_attr(map->domain, DOMAIN_ATTR_ATOMIC, &attr); ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_FAST, &fast); if (ret) { GPI_ERR(gpi_dev, "error setting ATTTR_ATOMIC, ret:%d\n", ret); goto error_smmu; GPI_ERR(gpi_dev, "Failed to set attr FAST, ret:%d\n", ret); goto release_mapping; } } attr = 1; ret = iommu_domain_set_attr(map->domain, DOMAIN_ATTR_S1_BYPASS, &attr); if (gpi_dev->smmu_cfg & GPI_SMMU_ATOMIC) { int atomic = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_ATOMIC, &atomic); if (ret) { GPI_ERR(gpi_dev, "error setting S1_BYPASS, ret:%d\n", ret); goto error_smmu; GPI_ERR(gpi_dev, "Failed to set attr ATOMIC, ret:%d\n", ret); goto release_mapping; } } ret = arm_iommu_attach_device(gpi_dev->dev, map); ret = arm_iommu_attach_device(gpi_dev->dev, mapping); if (ret) { GPI_ERR(gpi_dev, "error iommu_attach, ret:%d\n", ret); goto error_smmu; GPI_ERR(gpi_dev, "Failed with iommu_attach, ret:%d\n", ret); goto release_mapping; } } ret = dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(64)); ret = gpi_dma_mask(gpi_dev); if (ret) { GPI_ERR(gpi_dev, "error setting dma_mask, ret:%d\n", ret); GPI_ERR(gpi_dev, "Error setting dma_mask, ret:%d\n", ret); goto error_set_mask; } return ret; error_set_mask: if (gpi_dev->smmu_cfg) arm_iommu_detach_device(gpi_dev->dev); error_smmu: arm_iommu_release_mapping(map); release_mapping: if (mapping) arm_iommu_release_mapping(mapping); return ret; } Loading Loading @@ -2656,6 +2786,36 @@ static int gpi_probe(struct platform_device *pdev) return ret; } ret = of_property_read_u32(gpi_dev->dev->of_node, "qcom,smmu-cfg", &gpi_dev->smmu_cfg); if (ret) { GPI_ERR(gpi_dev, "missing 'qcom,smmu-cfg' DT node\n"); return ret; } if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) { u64 iova_range[2]; ret = of_property_count_elems_of_size(gpi_dev->dev->of_node, "qcom,iova-range", sizeof(iova_range)); if (ret != 1) { GPI_ERR(gpi_dev, "missing or incorrect 'qcom,iova-range' DT node ret:%d\n", ret); } ret = of_property_read_u64_array(gpi_dev->dev->of_node, "qcom,iova-range", iova_range, sizeof(iova_range) / sizeof(u64)); if (ret) { GPI_ERR(gpi_dev, "could not read DT prop 'qcom,iova-range\n"); return ret; } gpi_dev->iova_base = iova_range[0]; gpi_dev->iova_size = iova_range[1]; } ret = gpi_smmu_init(gpi_dev); if (ret) { GPI_ERR(gpi_dev, "error configuring smmu, ret:%d\n", ret); Loading Loading
Documentation/devicetree/bindings/dma/qcom_gpi.txt +25 −8 Original line number Diff line number Diff line Loading @@ -12,13 +12,12 @@ Main node properties: - #dma-cells Usage: required Value type: <u32> Definition: Number of parameters client will provide. Must be set to 6. 1st parameter: gpii index 2nd parameter: channel index 3rd parameter: serial engine index 4th parameter: bus protocol, 1 for SPI, 2 for UART, 3 for I2C 5th parameter: channel ring length in transfer ring elements 6th parameter: event processing priority, set to 0 for lowest latency Definition: Number of parameters client will provide. Must be set to 5. 1st parameter: channel index, 0 for TX, 1 for RX 2nd parameter: serial engine index 3rd parameter: bus protocol, 1 for SPI, 2 for UART, 3 for I2C 4th parameter: channel ring length in transfer ring elements 5th parameter: event processing priority, set to 0 for lowest latency - compatible Usage: required Loading Loading @@ -64,11 +63,27 @@ Main node properties: for the controller. For more detail please check binding documentation arm,smmu.txt - qcom,smmu-cfg Usage: required Value type: <u32> Definition: Determine whether GPI driver require to configure SMMU that sits behind GPI controller. Bit mask: BIT(0) : Attach address mapping to endpoint device BIT(1) : Set SMMU attribute S1_BYPASS BIT(2) : Set SMMU attribute FAST BIT(3) : Set SMMU attribute ATOMIC - qcom,iova-range Usage: required if SMMU S1 translation is enabled Value type: Array of <u64> Definition: Pair of values describing iova base and size to allocate. ======== Example: ======== gpi_dma0: qcom,gpi-dma@0x800000 { #dma-cells = <6>; #dma-cells = <5>; compatible = "qcom,gpi-dma"; reg = <0x800000 0x60000>; reg-names = "gpi-top"; Loading @@ -80,5 +95,7 @@ gpi_dma0: qcom,gpi-dma@0x800000 { qcom,gpii-mask = <0xfa>; qcom,ev-factor = <2>; iommus = <&apps_smmu 0x0016 0x0>; qcom,smmu-cfg = <0x1> qcom,iova-range = <0x0 0x100000 0x0 0x100000>; status = "ok"; };
arch/arm64/boot/dts/qcom/sdm845.dtsi +6 −2 Original line number Diff line number Diff line Loading @@ -3558,7 +3558,7 @@ }; gpi_dma0: qcom,gpi-dma@0x800000 { #dma-cells = <6>; #dma-cells = <5>; compatible = "qcom,gpi-dma"; reg = <0x800000 0x60000>; reg-names = "gpi-top"; Loading @@ -3570,11 +3570,13 @@ qcom,gpii-mask = <0xfa>; qcom,ev-factor = <2>; iommus = <&apps_smmu 0x0016 0x0>; qcom,smmu-cfg = <0x1>; qcom,iova-range = <0x0 0x100000 0x0 0x100000>; status = "ok"; }; gpi_dma1: qcom,gpi-dma@0xa00000 { #dma-cells = <6>; #dma-cells = <5>; compatible = "qcom,gpi-dma"; reg = <0xa00000 0x60000>; reg-names = "gpi-top"; Loading @@ -3586,6 +3588,8 @@ qcom,gpii-mask = <0xfa>; qcom,ev-factor = <2>; iommus = <&apps_smmu 0x06d6 0x0>; qcom,smmu-cfg = <0x1>; qcom,iova-range = <0x0 0x100000 0x0 0x100000>; status = "ok"; }; Loading
drivers/dma/qcom/gpi.c +205 −45 Original line number Diff line number Diff line Loading @@ -131,9 +131,11 @@ enum EV_PRIORITY { #define GPI_LABEL_SIZE (256) #define GPI_DBG_COMMON (99) #define MAX_CHANNELS_PER_GPII (2) #define GPI_TX_CHAN (0) #define GPI_RX_CHAN (1) #define CMD_TIMEOUT_MS (50) #define STATE_IGNORE (U32_MAX) #define REQ_OF_DMA_ARGS (6) /* # of arguments required from client */ #define REQ_OF_DMA_ARGS (5) /* # of arguments required from client */ struct __packed gpi_error_log_entry { u32 routine : 4; Loading Loading @@ -437,6 +439,9 @@ struct gpi_dev { u32 max_gpii; /* maximum # of gpii instances available per gpi block */ u32 gpii_mask; /* gpii instances available for apps */ u32 ev_factor; /* ev ring length factor */ u32 smmu_cfg; dma_addr_t iova_base; size_t iova_size; struct gpii *gpiis; void *ilctxt; u32 ipc_log_lvl; Loading Loading @@ -509,6 +514,11 @@ struct gpi_desc { struct gpii_chan *gpii_chan; }; #define GPI_SMMU_ATTACH BIT(0) #define GPI_SMMU_S1_BYPASS BIT(1) #define GPI_SMMU_FAST BIT(2) #define GPI_SMMU_ATOMIC BIT(3) const u32 GPII_CHAN_DIR[MAX_CHANNELS_PER_GPII] = { GPI_CHTYPE_DIR_OUT, GPI_CHTYPE_DIR_IN }; Loading Loading @@ -2464,12 +2474,53 @@ static int gpi_alloc_chan_resources(struct dma_chan *chan) return ret; } static int gpi_find_avail_gpii(struct gpi_dev *gpi_dev, u32 seid) { int gpii; struct gpii_chan *tx_chan, *rx_chan; /* check if same seid is already configured for another chid */ for (gpii = 0; gpii < gpi_dev->max_gpii; gpii++) { if (!((1 << gpii) & gpi_dev->gpii_mask)) continue; tx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_TX_CHAN]; rx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_RX_CHAN]; if (rx_chan->vc.chan.client_count && rx_chan->seid == seid) return gpii; if (tx_chan->vc.chan.client_count && tx_chan->seid == seid) return gpii; } /* no channels configured with same seid, return next avail gpii */ for (gpii = 0; gpii < gpi_dev->max_gpii; gpii++) { if (!((1 << gpii) & gpi_dev->gpii_mask)) continue; tx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_TX_CHAN]; rx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_RX_CHAN]; /* check if gpii is configured */ if (tx_chan->vc.chan.client_count || rx_chan->vc.chan.client_count) continue; /* found a free gpii */ return gpii; } /* no gpii instance available to use */ return -EIO; } /* gpi_of_dma_xlate: open client requested channel */ static struct dma_chan *gpi_of_dma_xlate(struct of_phandle_args *args, struct of_dma *of_dma) { struct gpi_dev *gpi_dev = (struct gpi_dev *)of_dma->of_dma_data; u32 gpii, chid; u32 seid, chid; int gpii; struct gpii_chan *gpii_chan; if (args->args_count < REQ_OF_DMA_ARGS) { Loading @@ -2479,25 +2530,33 @@ static struct dma_chan *gpi_of_dma_xlate(struct of_phandle_args *args, return NULL; } /* Check if valid gpii instance */ gpii = args->args[0]; if (!((1 << gpii) & gpi_dev->gpii_mask)) { GPI_ERR(gpi_dev, "gpii instance:%d is not supported\n", gpii); chid = args->args[0]; if (chid >= MAX_CHANNELS_PER_GPII) { GPI_ERR(gpi_dev, "gpii channel:%d not valid\n", chid); return NULL; } chid = args->args[1]; if (chid >= MAX_CHANNELS_PER_GPII) { GPI_ERR(gpi_dev, "gpii channel:%d not valid\n", chid); seid = args->args[1]; /* find next available gpii to use */ gpii = gpi_find_avail_gpii(gpi_dev, seid); if (gpii < 0) { GPI_ERR(gpi_dev, "no available gpii instances\n"); return NULL; } /* get ring size, protocol, se_id, and priority */ gpii_chan = &gpi_dev->gpiis[gpii].gpii_chan[chid]; gpii_chan->seid = args->args[2]; gpii_chan->protocol = args->args[3]; gpii_chan->req_tres = args->args[4]; gpii_chan->priority = args->args[5]; if (gpii_chan->vc.chan.client_count) { GPI_ERR(gpi_dev, "gpii:%d chid:%d seid:%d already configured\n", gpii, chid, gpii_chan->seid); return NULL; } /* get ring size, protocol, se_id, and priority */ gpii_chan->seid = seid; gpii_chan->protocol = args->args[2]; gpii_chan->req_tres = args->args[3]; gpii_chan->priority = args->args[4]; GPI_LOG(gpi_dev, "client req. gpii:%u chid:%u #_tre:%u priority:%u protocol:%u\n", Loading Loading @@ -2562,52 +2621,123 @@ static void gpi_setup_debug(struct gpi_dev *gpi_dev) } } static struct dma_iommu_mapping *gpi_create_mapping(struct gpi_dev *gpi_dev) { dma_addr_t base; size_t size; /* * If S1_BYPASS enabled then iommu space is not used, however framework * still require clients to create a mapping space before attaching. So * set to smallest size required by iommu framework. */ if (gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS) { base = 0; size = PAGE_SIZE; } else { base = gpi_dev->iova_base; size = gpi_dev->iova_size; } GPI_LOG(gpi_dev, "Creating iommu mapping of base:0x%llx size:%lu\n", base, size); return arm_iommu_create_mapping(&platform_bus_type, base, size); } static int gpi_dma_mask(struct gpi_dev *gpi_dev) { int mask = 64; if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) { unsigned long addr; addr = gpi_dev->iova_base + gpi_dev->iova_size + 1; mask = find_last_bit(&addr, 64); } GPI_LOG(gpi_dev, "Setting dma mask to %d\n", mask); return dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(mask)); } static int gpi_smmu_init(struct gpi_dev *gpi_dev) { u64 size = PAGE_SIZE; dma_addr_t base = 0x0; struct dma_iommu_mapping *map; int attr, ret; struct dma_iommu_mapping *mapping = NULL; int ret; map = arm_iommu_create_mapping(&platform_bus_type, base, size); if (IS_ERR_OR_NULL(map)) { ret = PTR_ERR(map) ? : -EIO; GPI_ERR(gpi_dev, "error create_mapping, ret:%d\n", ret); return ret; if (gpi_dev->smmu_cfg) { /* create mapping table */ mapping = gpi_create_mapping(gpi_dev); if (IS_ERR(mapping)) { GPI_ERR(gpi_dev, "Failed to create iommu mapping, ret:%ld\n", PTR_ERR(mapping)); return PTR_ERR(mapping); } if (gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS) { int s1_bypass = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, &s1_bypass); if (ret) { GPI_ERR(gpi_dev, "Failed to set attr S1_BYPASS, ret:%d\n", ret); goto release_mapping; } } if (gpi_dev->smmu_cfg & GPI_SMMU_FAST) { int fast = 1; attr = 1; ret = iommu_domain_set_attr(map->domain, DOMAIN_ATTR_ATOMIC, &attr); ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_FAST, &fast); if (ret) { GPI_ERR(gpi_dev, "error setting ATTTR_ATOMIC, ret:%d\n", ret); goto error_smmu; GPI_ERR(gpi_dev, "Failed to set attr FAST, ret:%d\n", ret); goto release_mapping; } } attr = 1; ret = iommu_domain_set_attr(map->domain, DOMAIN_ATTR_S1_BYPASS, &attr); if (gpi_dev->smmu_cfg & GPI_SMMU_ATOMIC) { int atomic = 1; ret = iommu_domain_set_attr(mapping->domain, DOMAIN_ATTR_ATOMIC, &atomic); if (ret) { GPI_ERR(gpi_dev, "error setting S1_BYPASS, ret:%d\n", ret); goto error_smmu; GPI_ERR(gpi_dev, "Failed to set attr ATOMIC, ret:%d\n", ret); goto release_mapping; } } ret = arm_iommu_attach_device(gpi_dev->dev, map); ret = arm_iommu_attach_device(gpi_dev->dev, mapping); if (ret) { GPI_ERR(gpi_dev, "error iommu_attach, ret:%d\n", ret); goto error_smmu; GPI_ERR(gpi_dev, "Failed with iommu_attach, ret:%d\n", ret); goto release_mapping; } } ret = dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(64)); ret = gpi_dma_mask(gpi_dev); if (ret) { GPI_ERR(gpi_dev, "error setting dma_mask, ret:%d\n", ret); GPI_ERR(gpi_dev, "Error setting dma_mask, ret:%d\n", ret); goto error_set_mask; } return ret; error_set_mask: if (gpi_dev->smmu_cfg) arm_iommu_detach_device(gpi_dev->dev); error_smmu: arm_iommu_release_mapping(map); release_mapping: if (mapping) arm_iommu_release_mapping(mapping); return ret; } Loading Loading @@ -2656,6 +2786,36 @@ static int gpi_probe(struct platform_device *pdev) return ret; } ret = of_property_read_u32(gpi_dev->dev->of_node, "qcom,smmu-cfg", &gpi_dev->smmu_cfg); if (ret) { GPI_ERR(gpi_dev, "missing 'qcom,smmu-cfg' DT node\n"); return ret; } if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) { u64 iova_range[2]; ret = of_property_count_elems_of_size(gpi_dev->dev->of_node, "qcom,iova-range", sizeof(iova_range)); if (ret != 1) { GPI_ERR(gpi_dev, "missing or incorrect 'qcom,iova-range' DT node ret:%d\n", ret); } ret = of_property_read_u64_array(gpi_dev->dev->of_node, "qcom,iova-range", iova_range, sizeof(iova_range) / sizeof(u64)); if (ret) { GPI_ERR(gpi_dev, "could not read DT prop 'qcom,iova-range\n"); return ret; } gpi_dev->iova_base = iova_range[0]; gpi_dev->iova_size = iova_range[1]; } ret = gpi_smmu_init(gpi_dev); if (ret) { GPI_ERR(gpi_dev, "error configuring smmu, ret:%d\n", ret); Loading