Re: [Freedreno] [PATCH v1 0/4] msm/gpu/a6xx: use the DMA-API for GMU memory allocations

2020-02-19 Thread John Stultz
On Wed, Feb 19, 2020 at 1:33 PM Jordan Crouse  wrote:
>
> When CONFIG_INIT_ON_ALLOC_DEFAULT_ON the GMU memory allocator runs afoul of
> cache coherency issues because it is mapped as write-combine without clearing
> the cache after it was zeroed.
>
> Rather than duplicate the hacky workaround we use in the GEM allocator for the
> same reason it turns out that we don't need to have a bespoke memory allocator
> for the GMU anyway. It uses a flat, global address space and there are only
> two relatively minor allocations anyway. In short, this is essentially what 
> the
> DMA API was created for so replace a bunch of memory management code with two
> calls to allocate and free DMA memory and we're fine.
>
> The only wrinkle is that the memory allocations need to be in a very specific
> location in the GMU virtual address space so in order to get the iova 
> allocator
> to do the right thing we need to specify the dma-ranges property in the device
> tree for the GMU node. Since we've not yet converted the GMU bindings over to
> YAML two patches quickly turn into four but at the end of it we have at least
> one bindings file converted to YAML and 99 less lines of code to worry about.
>
> Jordan Crouse (4):
>   dt-bindings: display: msm: Convert GMU bindings to YAML
>   dt-bindings: display: msm: Add required dma-range property
>   arm64: dts: sdm845: Set the virtual address range for GMU allocations
>   drm/msm/a6xx: Use the DMA API for GMU memory objects

Awesome! Thanks so much for the quick turnaround on this! This set
resolves the crashes I was seeing with
CONFIG_INIT_ON_ALLOC_DEFAULT_ON.

Tested-by: John Stultz 

thanks again!
-john
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH v1 2/4] dt-bindings: display: msm: Add required dma-range property

2020-02-19 Thread Jordan Crouse
The GMU node now requires a specific dma-range property so that the driver
can use the DMA API to do the few memory allocations required by the GMU.
This sets the IOMMU iova allocadtor to match the 'uncached' part of the
GMU virtual address space.

Signed-off-by: Jordan Crouse 
---

 Documentation/devicetree/bindings/display/msm/gmu.yaml | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/msm/gmu.yaml 
b/Documentation/devicetree/bindings/display/msm/gmu.yaml
index 776ff92..6952d5a 100644
--- a/Documentation/devicetree/bindings/display/msm/gmu.yaml
+++ b/Documentation/devicetree/bindings/display/msm/gmu.yaml
@@ -83,6 +83,13 @@ properties:
   Phandle to the OPP table for the available GMU frequencies. Refer to
   ../../opp/opp.txt for more information.
 
+  dma-ranges:
+$ref: /schemas/types.yaml#/definitions/uint32-array
+description:
+  Describe the dma-address range for the device. This should always
+  describe the range between 0x6000 and 0x8000 which represents
+  the uncached region of the GMU address space.
+
 required:
   - compatible
   - reg
@@ -95,6 +102,7 @@ required:
   - power-domain-names
   - iommus
   - operating-points-v2
+  - dma-ranges
 
 examples:
  - |
@@ -127,4 +135,6 @@ examples:
 
 iommus = <&adreno_smmu 5>;
 operating-points-v2 = <&gmu_opp_table>;
+
+dma-ranges = <0 0x6000 0 0x6000 0 0x8000>;
};
-- 
2.7.4
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH v1 4/4] drm/msm/a6xx: Use the DMA API for GMU memory objects

2020-02-19 Thread Jordan Crouse
The GMU has very few memory allocations and uses a flat memory space so
there is no good reason to go out of our way to bypass the DMA APIs which
were basically designed for this exact secnario.

Signed-off-by: Jordan Crouse 
---

 drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 107 ++
 drivers/gpu/drm/msm/adreno/a6xx_gmu.h |   5 +-
 2 files changed, 7 insertions(+), 105 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c 
b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 983afea..97c9ddf 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -2,6 +2,7 @@
 /* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. */
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -895,21 +896,10 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
 
 static void a6xx_gmu_memory_free(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo)
 {
-   int count, i;
-   u64 iova;
-
if (IS_ERR_OR_NULL(bo))
return;
 
-   count = bo->size >> PAGE_SHIFT;
-   iova = bo->iova;
-
-   for (i = 0; i < count; i++, iova += PAGE_SIZE) {
-   iommu_unmap(gmu->domain, iova, PAGE_SIZE);
-   __free_pages(bo->pages[i], 0);
-   }
-
-   kfree(bo->pages);
+   dma_free_attrs(gmu->dev, bo->size, bo->virt, bo->iova, bo->attrs);
kfree(bo);
 }
 
@@ -917,94 +907,23 @@ static struct a6xx_gmu_bo *a6xx_gmu_memory_alloc(struct 
a6xx_gmu *gmu,
size_t size)
 {
struct a6xx_gmu_bo *bo;
-   int ret, count, i;
 
bo = kzalloc(sizeof(*bo), GFP_KERNEL);
if (!bo)
return ERR_PTR(-ENOMEM);
 
bo->size = PAGE_ALIGN(size);
+   bo->attrs = DMA_ATTR_WRITE_COMBINE;
 
-   count = bo->size >> PAGE_SHIFT;
+   bo->virt = dma_alloc_attrs(gmu->dev, bo->size, &bo->iova, GFP_KERNEL,
+   bo->attrs);
 
-   bo->pages = kcalloc(count, sizeof(struct page *), GFP_KERNEL);
-   if (!bo->pages) {
+   if (!bo->virt) {
kfree(bo);
return ERR_PTR(-ENOMEM);
}
 
-   for (i = 0; i < count; i++) {
-   bo->pages[i] = alloc_page(GFP_KERNEL);
-   if (!bo->pages[i])
-   goto err;
-   }
-
-   bo->iova = gmu->uncached_iova_base;
-
-   for (i = 0; i < count; i++) {
-   ret = iommu_map(gmu->domain,
-   bo->iova + (PAGE_SIZE * i),
-   page_to_phys(bo->pages[i]), PAGE_SIZE,
-   IOMMU_READ | IOMMU_WRITE);
-
-   if (ret) {
-   DRM_DEV_ERROR(gmu->dev, "Unable to map GMU buffer 
object\n");
-
-   for (i = i - 1 ; i >= 0; i--)
-   iommu_unmap(gmu->domain,
-   bo->iova + (PAGE_SIZE * i),
-   PAGE_SIZE);
-
-   goto err;
-   }
-   }
-
-   bo->virt = vmap(bo->pages, count, VM_IOREMAP,
-   pgprot_writecombine(PAGE_KERNEL));
-   if (!bo->virt)
-   goto err;
-
-   /* Align future IOVA addresses on 1MB boundaries */
-   gmu->uncached_iova_base += ALIGN(size, SZ_1M);
-
return bo;
-
-err:
-   for (i = 0; i < count; i++) {
-   if (bo->pages[i])
-   __free_pages(bo->pages[i], 0);
-   }
-
-   kfree(bo->pages);
-   kfree(bo);
-
-   return ERR_PTR(-ENOMEM);
-}
-
-static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu)
-{
-   int ret;
-
-   /*
-* The GMU address space is hardcoded to treat the range
-* 0x6000 - 0x8000 as un-cached memory. All buffers shared
-* between the GMU and the CPU will live in this space
-*/
-   gmu->uncached_iova_base = 0x6000;
-
-
-   gmu->domain = iommu_domain_alloc(&platform_bus_type);
-   if (!gmu->domain)
-   return -ENODEV;
-
-   ret = iommu_attach_device(gmu->domain, gmu->dev);
-
-   if (ret) {
-   iommu_domain_free(gmu->domain);
-   gmu->domain = NULL;
-   }
-
-   return ret;
 }
 
 /* Return the 'arc-level' for the given frequency */
@@ -1264,10 +1183,6 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
 
a6xx_gmu_memory_free(gmu, gmu->hfi);
 
-   iommu_detach_device(gmu->domain, gmu->dev);
-
-   iommu_domain_free(gmu->domain);
-
free_irq(gmu->gmu_irq, gmu);
free_irq(gmu->hfi_irq, gmu);
 
@@ -1300,11 +1215,6 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct 
device_node *node)
if (ret)
goto err_put_device;
 
-   /* Set up the IOMMU context bank */
-   ret = a6xx_gmu_memory_probe(gmu);
-   if (ret)
-   goto err_put_device;
-
/* Allocate memory for for the HFI queues */
gmu->hfi = a6xx_gmu_memory_alloc(gmu, SZ_16K);
if (IS_ERR(gmu->hfi))
@@ -1350,11 +1260,6 @@ 

[Freedreno] [PATCH v1 1/4] dt-bindings: display: msm: Convert GMU bindings to YAML

2020-02-19 Thread Jordan Crouse
Convert display/msm/gmu.txt to display/msm/gmu.yaml and remove the old
text bindings.

Signed-off-by: Jordan Crouse 
---

 .../devicetree/bindings/display/msm/gmu.txt| 116 --
 .../devicetree/bindings/display/msm/gmu.yaml   | 130 +
 2 files changed, 130 insertions(+), 116 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/display/msm/gmu.txt
 create mode 100644 Documentation/devicetree/bindings/display/msm/gmu.yaml

diff --git a/Documentation/devicetree/bindings/display/msm/gmu.txt 
b/Documentation/devicetree/bindings/display/msm/gmu.txt
deleted file mode 100644
index bf9c7a2..000
--- a/Documentation/devicetree/bindings/display/msm/gmu.txt
+++ /dev/null
@@ -1,116 +0,0 @@
-Qualcomm adreno/snapdragon GMU (Graphics management unit)
-
-The GMU is a programmable power controller for the GPU. the CPU controls the
-GMU which in turn handles power controls for the GPU.
-
-Required properties:
-- compatible: "qcom,adreno-gmu-XYZ.W", "qcom,adreno-gmu"
-for example: "qcom,adreno-gmu-630.2", "qcom,adreno-gmu"
-  Note that you need to list the less specific "qcom,adreno-gmu"
-  for generic matches and the more specific identifier to identify
-  the specific device.
-- reg: Physical base address and length of the GMU registers.
-- reg-names: Matching names for the register regions
-  * "gmu"
-  * "gmu_pdc"
-  * "gmu_pdc_seg"
-- interrupts: The interrupt signals from the GMU.
-- interrupt-names: Matching names for the interrupts
-  * "hfi"
-  * "gmu"
-- clocks: phandles to the device clocks
-- clock-names: Matching names for the clocks
-   * "gmu"
-   * "cxo"
-   * "axi"
-   * "mnoc"
-- power-domains: should be:
-   <&clock_gpucc GPU_CX_GDSC>
-   <&clock_gpucc GPU_GX_GDSC>
-- power-domain-names: Matching names for the power domains
-- iommus: phandle to the adreno iommu
-- operating-points-v2: phandle to the OPP operating points
-
-Optional properties:
-- sram: phandle to the On Chip Memory (OCMEM) that's present on some Snapdragon
-SoCs. See Documentation/devicetree/bindings/sram/qcom,ocmem.yaml.
-
-Example:
-
-/ {
-   ...
-
-   gmu: gmu@506a000 {
-   compatible="qcom,adreno-gmu-630.2", "qcom,adreno-gmu";
-
-   reg = <0x506a000 0x3>,
-   <0xb28 0x1>,
-   <0xb48 0x1>;
-   reg-names = "gmu", "gmu_pdc", "gmu_pdc_seq";
-
-   interrupts = ,
-;
-   interrupt-names = "hfi", "gmu";
-
-   clocks = <&gpucc GPU_CC_CX_GMU_CLK>,
-   <&gpucc GPU_CC_CXO_CLK>,
-   <&gcc GCC_DDRSS_GPU_AXI_CLK>,
-   <&gcc GCC_GPU_MEMNOC_GFX_CLK>;
-   clock-names = "gmu", "cxo", "axi", "memnoc";
-
-   power-domains = <&gpucc GPU_CX_GDSC>,
-   <&gpucc GPU_GX_GDSC>;
-   power-domain-names = "cx", "gx";
-
-   iommus = <&adreno_smmu 5>;
-
-   operating-points-v2 = <&gmu_opp_table>;
-   };
-};
-
-a3xx example with OCMEM support:
-
-/ {
-   ...
-
-   gpu: adreno@fdb0 {
-   compatible = "qcom,adreno-330.2",
-"qcom,adreno";
-   reg = <0xfdb0 0x1>;
-   reg-names = "kgsl_3d0_reg_memory";
-   interrupts = ;
-   interrupt-names = "kgsl_3d0_irq";
-   clock-names = "core",
- "iface",
- "mem_iface";
-   clocks = <&mmcc OXILI_GFX3D_CLK>,
-<&mmcc OXILICX_AHB_CLK>,
-<&mmcc OXILICX_AXI_CLK>;
-   sram = <&gmu_sram>;
-   power-domains = <&mmcc OXILICX_GDSC>;
-   operating-points-v2 = <&gpu_opp_table>;
-   iommus = <&gpu_iommu 0>;
-   };
-
-   ocmem@fdd0 {
-   compatible = "qcom,msm8974-ocmem";
-
-   reg = <0xfdd0 0x2000>,
- <0xfec0 0x18>;
-   reg-names = "ctrl",
-"mem";
-
-   clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>,
-<&mmcc OCMEMCX_OCMEMNOC_CLK>;
-   clock-names = "core",
- "iface";
-
-   #address-cells = <1>;
-   #size-cells = <1>;
-
-   gmu_sram: gmu-sram@0 {
-   reg = <0x0 0x10>;
-   ranges = <0 0 0xfec0 0x10>;
-   };
-   };
-};
diff --git a/Documentation/devicetree/bindings/display/msm/gmu.yaml 
b/Documentation/devicetree/bindings/display/msm/gmu.yaml
new file mode 100644
index 000..776ff92
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/gmu.yaml
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright 2019-2020, The Linux Foundation, All Rights Reserved
+%YAML 1.2
+---
+
+$id: "http:/

[Freedreno] [PATCH v1 0/4] msm/gpu/a6xx: use the DMA-API for GMU memory allocations

2020-02-19 Thread Jordan Crouse
When CONFIG_INIT_ON_ALLOC_DEFAULT_ON the GMU memory allocator runs afoul of
cache coherency issues because it is mapped as write-combine without clearing
the cache after it was zeroed.

Rather than duplicate the hacky workaround we use in the GEM allocator for the
same reason it turns out that we don't need to have a bespoke memory allocator
for the GMU anyway. It uses a flat, global address space and there are only
two relatively minor allocations anyway. In short, this is essentially what the
DMA API was created for so replace a bunch of memory management code with two
calls to allocate and free DMA memory and we're fine.

The only wrinkle is that the memory allocations need to be in a very specific
location in the GMU virtual address space so in order to get the iova allocator
to do the right thing we need to specify the dma-ranges property in the device
tree for the GMU node. Since we've not yet converted the GMU bindings over to
YAML two patches quickly turn into four but at the end of it we have at least
one bindings file converted to YAML and 99 less lines of code to worry about.

Jordan Crouse (4):
  dt-bindings: display: msm: Convert GMU bindings to YAML
  dt-bindings: display: msm: Add required dma-range property
  arm64: dts: sdm845: Set the virtual address range for GMU allocations
  drm/msm/a6xx: Use the DMA API for GMU memory objects

 .../devicetree/bindings/display/msm/gmu.txt| 116 -
 .../devicetree/bindings/display/msm/gmu.yaml   | 140 +
 arch/arm64/boot/dts/qcom/sdm845.dtsi   |   2 +
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c  | 107 +---
 drivers/gpu/drm/msm/adreno/a6xx_gmu.h  |   5 +-
 5 files changed, 149 insertions(+), 221 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/display/msm/gmu.txt
 create mode 100644 Documentation/devicetree/bindings/display/msm/gmu.yaml

-- 
2.7.4
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH 05/12] drm/msm/dpu: Stop copying around mode->private_flags

2020-02-19 Thread Ville Syrjala
From: Ville Syrjälä 

The driver never sets mode->private_flags so copying
it back and forth is entirely pointless. Stop doing it.

Also drop private_flags from the tracepoint.

Cc: Rob Clark 
Cc: Sean Paul 
Cc: linux-arm-...@vger.kernel.org
Cc: freedreno@lists.freedesktop.org
Signed-off-by: Ville Syrjälä 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 29 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h   | 10 +++
 2 files changed, 5 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 58d3400668f5..4511e2ba3680 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -500,23 +500,6 @@ void dpu_encoder_helper_split_config(
}
 }
 
-static void _dpu_encoder_adjust_mode(struct drm_connector *connector,
-   struct drm_display_mode *adj_mode)
-{
-   struct drm_display_mode *cur_mode;
-
-   if (!connector || !adj_mode)
-   return;
-
-   list_for_each_entry(cur_mode, &connector->modes, head) {
-   if (cur_mode->vdisplay == adj_mode->vdisplay &&
-   cur_mode->hdisplay == adj_mode->hdisplay &&
-   drm_mode_vrefresh(cur_mode) == drm_mode_vrefresh(adj_mode)) 
{
-   adj_mode->private_flags |= cur_mode->private_flags;
-   }
-   }
-}
-
 static struct msm_display_topology dpu_encoder_get_topology(
struct dpu_encoder_virt *dpu_enc,
struct dpu_kms *dpu_kms,
@@ -580,15 +563,6 @@ static int dpu_encoder_virt_atomic_check(
adj_mode = &crtc_state->adjusted_mode;
trace_dpu_enc_atomic_check(DRMID(drm_enc));
 
-   /*
-* display drivers may populate private fields of the drm display mode
-* structure while registering possible modes of a connector with DRM.
-* These private fields are not populated back while DRM invokes
-* the mode_set callbacks. This module retrieves and populates the
-* private fields of the given mode.
-*/
-   _dpu_encoder_adjust_mode(conn_state->connector, adj_mode);
-
/* perform atomic check on the first physical encoder (master) */
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
@@ -623,8 +597,7 @@ static int dpu_encoder_virt_atomic_check(
}
}
 
-   trace_dpu_enc_atomic_check_flags(DRMID(drm_enc), adj_mode->flags,
-   adj_mode->private_flags);
+   trace_dpu_enc_atomic_check_flags(DRMID(drm_enc), adj_mode->flags);
 
return ret;
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
index eecfe9b3199e..6714b088970f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
@@ -327,20 +327,18 @@ DEFINE_EVENT(dpu_enc_keyval_template, 
dpu_enc_trigger_start,
 );
 
 TRACE_EVENT(dpu_enc_atomic_check_flags,
-   TP_PROTO(uint32_t drm_id, unsigned int flags, int private_flags),
-   TP_ARGS(drm_id, flags, private_flags),
+   TP_PROTO(uint32_t drm_id, unsigned int flags),
+   TP_ARGS(drm_id, flags),
TP_STRUCT__entry(
__field(uint32_t,   drm_id  )
__field(unsigned int,   flags   )
-   __field(int,private_flags   )
),
TP_fast_assign(
__entry->drm_id = drm_id;
__entry->flags = flags;
-   __entry->private_flags = private_flags;
),
-   TP_printk("id=%u, flags=%u, private_flags=%d",
- __entry->drm_id, __entry->flags, __entry->private_flags)
+   TP_printk("id=%u, flags=%u",
+ __entry->drm_id, __entry->flags)
 );
 
 DECLARE_EVENT_CLASS(dpu_enc_id_enable_template,
-- 
2.24.1

___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH 4/4] drm/msm/dpu: Track resources in global state

2020-02-19 Thread Drew Davenport
Move mapping of resources to encoder ids from the resource manager to a
new dpu_global_state struct. Store this struct in global atomic state.

Before this patch, atomic test would be performed by modifying global
state (resource manager), and backing out any changes if the test fails.
By using drm atomic global state, this is not necessary as any changes
to the global state will be discarded if the test fails.

Signed-off-by: Drew Davenport 
---

 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |  65 +--
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  84 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h |  26 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c  | 121 ++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h  |  22 ++--
 5 files changed, 207 insertions(+), 111 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 6cadeff456f09..5afde2e7fef08 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -164,7 +164,6 @@ enum dpu_enc_rc_states {
  * clks and resources after IDLE_TIMEOUT time.
  * @vsync_event_work:  worker to handle vsync event for autorefresh
  * @topology:   topology of the display
- * @mode_set_complete:  flag to indicate modeset completion
  * @idle_timeout:  idle timeout duration in milliseconds
  */
 struct dpu_encoder_virt {
@@ -202,7 +201,6 @@ struct dpu_encoder_virt {
struct delayed_work delayed_off_work;
struct kthread_work vsync_event_work;
struct msm_display_topology topology;
-   bool mode_set_complete;
 
u32 idle_timeout;
 };
@@ -563,6 +561,7 @@ static int dpu_encoder_virt_atomic_check(
const struct drm_display_mode *mode;
struct drm_display_mode *adj_mode;
struct msm_display_topology topology;
+   struct dpu_global_state *global_state;
int i = 0;
int ret = 0;
 
@@ -579,6 +578,7 @@ static int dpu_encoder_virt_atomic_check(
dpu_kms = to_dpu_kms(priv->kms);
mode = &crtc_state->mode;
adj_mode = &crtc_state->adjusted_mode;
+   global_state = dpu_kms_get_existing_global_state(dpu_kms);
trace_dpu_enc_atomic_check(DRMID(drm_enc));
 
/*
@@ -610,17 +610,15 @@ static int dpu_encoder_virt_atomic_check(
 
topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode);
 
-   /* Reserve dynamic resources now. Indicating AtomicTest phase */
+   /* Reserve dynamic resources now. */
if (!ret) {
/*
 * Avoid reserving resources when mode set is pending. Topology
 * info may not be available to complete reservation.
 */
-   if (drm_atomic_crtc_needs_modeset(crtc_state)
-   && dpu_enc->mode_set_complete) {
-   ret = dpu_rm_reserve(&dpu_kms->rm, drm_enc, crtc_state,
-topology, true);
-   dpu_enc->mode_set_complete = false;
+   if (drm_atomic_crtc_needs_modeset(crtc_state)) {
+   ret = dpu_rm_reserve(&dpu_kms->rm, global_state,
+   drm_enc, crtc_state, topology);
}
}
 
@@ -957,12 +955,13 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder 
*drm_enc,
struct drm_connector *conn = NULL, *conn_iter;
struct drm_crtc *drm_crtc;
struct dpu_crtc_state *cstate;
+   struct dpu_global_state *global_state;
struct msm_display_topology topology;
struct dpu_hw_blk *hw_pp[MAX_CHANNELS_PER_ENC];
struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC];
struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC];
int num_lm, num_ctl, num_pp;
-   int i, j, ret;
+   int i, j;
 
if (!drm_enc) {
DPU_ERROR("invalid encoder\n");
@@ -976,6 +975,12 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder 
*drm_enc,
dpu_kms = to_dpu_kms(priv->kms);
connector_list = &dpu_kms->dev->mode_config.connector_list;
 
+   global_state = dpu_kms_get_existing_global_state(dpu_kms);
+   if (IS_ERR_OR_NULL(global_state)) {
+   DPU_ERROR("Failed to get global state");
+   return;
+   }
+
trace_dpu_enc_mode_set(DRMID(drm_enc));
 
list_for_each_entry(conn_iter, connector_list, head)
@@ -996,21 +1001,14 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder 
*drm_enc,
 
topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode);
 
-   /* Reserve dynamic resources now. Indicating non-AtomicTest phase */
-   ret = dpu_rm_reserve(&dpu_kms->rm, drm_enc, drm_crtc->state,
-topology, false);
-   if (ret) {
-   DPU_ERROR_ENC(dpu_enc,
-   "failed to reserve hw

[Freedreno] [PATCH 2/4] drm/msm/dpu: Refactor rm iterator

2020-02-19 Thread Drew Davenport
Make iterator implementation private, and add function to
query resources assigned to an encoder.

Signed-off-by: Drew Davenport 
---

 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 59 ---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h   | 10 
 .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h   | 10 
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c| 31 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h| 47 ++-
 5 files changed, 76 insertions(+), 81 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index f8ac3bf60fd60..6cadeff456f09 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -957,11 +957,11 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder 
*drm_enc,
struct drm_connector *conn = NULL, *conn_iter;
struct drm_crtc *drm_crtc;
struct dpu_crtc_state *cstate;
-   struct dpu_rm_hw_iter hw_iter;
struct msm_display_topology topology;
-   struct dpu_hw_ctl *hw_ctl[MAX_CHANNELS_PER_ENC] = { NULL };
-   struct dpu_hw_mixer *hw_lm[MAX_CHANNELS_PER_ENC] = { NULL };
-   int num_lm = 0, num_ctl = 0;
+   struct dpu_hw_blk *hw_pp[MAX_CHANNELS_PER_ENC];
+   struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC];
+   struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC];
+   int num_lm, num_ctl, num_pp;
int i, j, ret;
 
if (!drm_enc) {
@@ -1005,42 +1005,31 @@ static void dpu_encoder_virt_mode_set(struct 
drm_encoder *drm_enc,
return;
}
 
-   dpu_rm_init_hw_iter(&hw_iter, drm_enc->base.id, DPU_HW_BLK_PINGPONG);
-   for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
-   dpu_enc->hw_pp[i] = NULL;
-   if (!dpu_rm_get_hw(&dpu_kms->rm, &hw_iter))
-   break;
-   dpu_enc->hw_pp[i] = (struct dpu_hw_pingpong *) hw_iter.hw;
-   }
-
-   dpu_rm_init_hw_iter(&hw_iter, drm_enc->base.id, DPU_HW_BLK_CTL);
-   for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
-   if (!dpu_rm_get_hw(&dpu_kms->rm, &hw_iter))
-   break;
-   hw_ctl[i] = (struct dpu_hw_ctl *)hw_iter.hw;
-   num_ctl++;
-   }
+   num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, drm_enc->base.id,
+   DPU_HW_BLK_PINGPONG, hw_pp, ARRAY_SIZE(hw_pp));
+   num_ctl = dpu_rm_get_assigned_resources(&dpu_kms->rm, drm_enc->base.id,
+   DPU_HW_BLK_CTL, hw_ctl, ARRAY_SIZE(hw_ctl));
+   num_lm = dpu_rm_get_assigned_resources(&dpu_kms->rm, drm_enc->base.id,
+   DPU_HW_BLK_LM, hw_lm, ARRAY_SIZE(hw_lm));
 
-   dpu_rm_init_hw_iter(&hw_iter, drm_enc->base.id, DPU_HW_BLK_LM);
-   for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
-   if (!dpu_rm_get_hw(&dpu_kms->rm, &hw_iter))
-   break;
-   hw_lm[i] = (struct dpu_hw_mixer *)hw_iter.hw;
-   num_lm++;
-   }
+   for (i = 0; i < MAX_CHANNELS_PER_ENC; i++)
+   dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i])
+   : NULL;
 
cstate = to_dpu_crtc_state(drm_crtc->state);
 
for (i = 0; i < num_lm; i++) {
int ctl_idx = (i < num_ctl) ? i : (num_ctl-1);
 
-   cstate->mixers[i].hw_lm = hw_lm[i];
-   cstate->mixers[i].lm_ctl = hw_ctl[ctl_idx];
+   cstate->mixers[i].hw_lm = to_dpu_hw_mixer(hw_lm[i]);
+   cstate->mixers[i].lm_ctl = to_dpu_hw_ctl(hw_ctl[ctl_idx]);
}
 
cstate->num_mixers = num_lm;
 
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+   int num_blk;
+   struct dpu_hw_blk *hw_blk[MAX_CHANNELS_PER_ENC];
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
 
if (!dpu_enc->hw_pp[i]) {
@@ -1056,17 +1045,15 @@ static void dpu_encoder_virt_mode_set(struct 
drm_encoder *drm_enc,
}
 
phys->hw_pp = dpu_enc->hw_pp[i];
-   phys->hw_ctl = hw_ctl[i];
+   phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]);
 
-   dpu_rm_init_hw_iter(&hw_iter, drm_enc->base.id,
-   DPU_HW_BLK_INTF);
-   for (j = 0; j < MAX_CHANNELS_PER_ENC; j++) {
+   num_blk = dpu_rm_get_assigned_resources(&dpu_kms->rm,
+   drm_enc->base.id, DPU_HW_BLK_INTF, hw_blk,
+   ARRAY_SIZE(hw_blk));
+   for (j = 0; j < num_blk; j++) {
struct dpu_hw_intf *hw_intf;
 
-   if (!dpu_rm_get_hw(&dpu_kms->rm, &hw_iter))
-   break;
-
-   hw_intf = (struct dpu_hw_intf *)hw_iter.hw;
+   hw_intf = to_dpu_hw_intf(hw_blk[i]);
if (hw_intf->idx == phys->intf_idx)
phys->hw_in

[Freedreno] [PATCH 3/4] drm/msm/dpu: Refactor resource manager

2020-02-19 Thread Drew Davenport
Track hardware resource objects in arrays rather than
a list and remove the resource manager's iterator idiom. Separate
the mapping of hardware resources to an encoder ID into a different
array.

Use an implicit mapping between the hardware blocks' ids, which
are 1-based, and array indices in these arrays to replace iteration
with index lookups in several places.

Signed-off-by: Drew Davenport 
---

 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 553 +++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h |  22 +-
 2 files changed, 255 insertions(+), 320 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index 779df26dc81ae..f1483b00b7423 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -12,8 +12,12 @@
 #include "dpu_encoder.h"
 #include "dpu_trace.h"
 
-#define RESERVED_BY_OTHER(h, r)  \
-   ((h)->enc_id && (h)->enc_id != r)
+
+static inline bool reserved_by_other(uint32_t *res_map, int idx,
+uint32_t enc_id)
+{
+   return res_map[idx] && res_map[idx] != enc_id;
+}
 
 /**
  * struct dpu_rm_requirements - Reservation requirements parameter bundle
@@ -25,126 +29,40 @@ struct dpu_rm_requirements {
struct dpu_encoder_hw_resources hw_res;
 };
 
-
-/**
- * struct dpu_rm_hw_blk - hardware block tracking list member
- * @list:  List head for list of all hardware blocks tracking items
- * @id:Hardware ID number, within it's own space, ie. LM_X
- * @enc_id:Encoder id to which this blk is binded
- * @hw:Pointer to the hardware register access object for this 
block
- */
-struct dpu_rm_hw_blk {
-   struct list_head list;
-   uint32_t id;
-   uint32_t enc_id;
-   struct dpu_hw_blk *hw;
-};
-
-/**
- * struct dpu_rm_hw_iter - iterator for use with dpu_rm
- * @hw: dpu_hw object requested, or NULL on failure
- * @blk: dpu_rm internal block representation. Clients ignore. Used as 
iterator.
- * @enc_id: DRM ID of Encoder client wishes to search for, or 0 for Any Encoder
- * @type: Hardware Block Type client wishes to search for.
- */
-struct dpu_rm_hw_iter {
-   void *hw;
-   struct dpu_rm_hw_blk *blk;
-   uint32_t enc_id;
-   enum dpu_hw_blk_type type;
-};
-
-static void dpu_rm_init_hw_iter(
-   struct dpu_rm_hw_iter *iter,
-   uint32_t enc_id,
-   enum dpu_hw_blk_type type)
-{
-   memset(iter, 0, sizeof(*iter));
-   iter->enc_id = enc_id;
-   iter->type = type;
-}
-
-static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i)
+int dpu_rm_destroy(struct dpu_rm *rm)
 {
-   struct list_head *blk_list;
+   int i;
 
-   if (!rm || !i || i->type >= DPU_HW_BLK_MAX) {
-   DPU_ERROR("invalid rm\n");
-   return false;
-   }
+   for (i = 0; i < ARRAY_SIZE(rm->pingpong_blks); i++) {
+   struct dpu_hw_pingpong *hw;
 
-   i->hw = NULL;
-   blk_list = &rm->hw_blks[i->type];
-
-   if (i->blk && (&i->blk->list == blk_list)) {
-   DPU_DEBUG("attempt resume iteration past last\n");
-   return false;
+   if (rm->pingpong_blks[i]) {
+   hw = to_dpu_hw_pingpong(rm->pingpong_blks[i]);
+   dpu_hw_pingpong_destroy(hw);
+   }
}
+   for (i = 0; i < ARRAY_SIZE(rm->mixer_blks); i++) {
+   struct dpu_hw_mixer *hw;
 
-   i->blk = list_prepare_entry(i->blk, blk_list, list);
-
-   list_for_each_entry_continue(i->blk, blk_list, list) {
-   if (i->enc_id == i->blk->enc_id) {
-   i->hw = i->blk->hw;
-   DPU_DEBUG("found type %d id %d for enc %d\n",
-   i->type, i->blk->id, i->enc_id);
-   return true;
+   if (rm->mixer_blks[i]) {
+   hw = to_dpu_hw_mixer(rm->mixer_blks[i]);
+   dpu_hw_lm_destroy(hw);
}
}
+   for (i = 0; i < ARRAY_SIZE(rm->ctl_blks); i++) {
+   struct dpu_hw_ctl *hw;
 
-   DPU_DEBUG("no match, type %d for enc %d\n", i->type, i->enc_id);
-
-   return false;
-}
-
-static bool dpu_rm_get_hw(struct dpu_rm *rm, struct dpu_rm_hw_iter *i)
-{
-   bool ret;
-
-   mutex_lock(&rm->rm_lock);
-   ret = _dpu_rm_get_hw_locked(rm, i);
-   mutex_unlock(&rm->rm_lock);
-
-   return ret;
-}
-
-static void _dpu_rm_hw_destroy(enum dpu_hw_blk_type type, void *hw)
-{
-   switch (type) {
-   case DPU_HW_BLK_LM:
-   dpu_hw_lm_destroy(hw);
-   break;
-   case DPU_HW_BLK_CTL:
-   dpu_hw_ctl_destroy(hw);
-   break;
-   case DPU_HW_BLK_PINGPONG:
-   dpu_hw_pingpong_destroy(hw);
-   break;
-   case DPU_HW_BLK_INTF:
-   dpu_hw_intf_destroy(hw);
-   

[Freedreno] [PATCH 1/4] drm/msm/dpu: Remove unused function arguments

2020-02-19 Thread Drew Davenport
Several functions arguments in the resource manager are unused, so
remove them.

Signed-off-by: Drew Davenport 
---

 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 37 ++
 1 file changed, 14 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index 23f5b1433b357..dea1dba441fe7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -144,8 +144,7 @@ static int _dpu_rm_hw_blk_create(
const struct dpu_mdss_cfg *cat,
void __iomem *mmio,
enum dpu_hw_blk_type type,
-   uint32_t id,
-   const void *hw_catalog_info)
+   uint32_t id)
 {
struct dpu_rm_hw_blk *blk;
void *hw;
@@ -223,7 +222,7 @@ int dpu_rm_init(struct dpu_rm *rm,
}
 
rc = _dpu_rm_hw_blk_create(rm, cat, mmio, DPU_HW_BLK_LM,
-   cat->mixer[i].id, &cat->mixer[i]);
+   cat->mixer[i].id);
if (rc) {
DPU_ERROR("failed: lm hw not available\n");
goto fail;
@@ -244,7 +243,7 @@ int dpu_rm_init(struct dpu_rm *rm,
 
for (i = 0; i < cat->pingpong_count; i++) {
rc = _dpu_rm_hw_blk_create(rm, cat, mmio, DPU_HW_BLK_PINGPONG,
-   cat->pingpong[i].id, &cat->pingpong[i]);
+   cat->pingpong[i].id);
if (rc) {
DPU_ERROR("failed: pp hw not available\n");
goto fail;
@@ -258,7 +257,7 @@ int dpu_rm_init(struct dpu_rm *rm,
}
 
rc = _dpu_rm_hw_blk_create(rm, cat, mmio, DPU_HW_BLK_INTF,
-   cat->intf[i].id, &cat->intf[i]);
+   cat->intf[i].id);
if (rc) {
DPU_ERROR("failed: intf hw not available\n");
goto fail;
@@ -267,7 +266,7 @@ int dpu_rm_init(struct dpu_rm *rm,
 
for (i = 0; i < cat->ctl_count; i++) {
rc = _dpu_rm_hw_blk_create(rm, cat, mmio, DPU_HW_BLK_CTL,
-   cat->ctl[i].id, &cat->ctl[i]);
+   cat->ctl[i].id);
if (rc) {
DPU_ERROR("failed: ctl hw not available\n");
goto fail;
@@ -293,7 +292,6 @@ static bool _dpu_rm_needs_split_display(const struct 
msm_display_topology *top)
  * pingpong
  * @rm: dpu resource manager handle
  * @enc_id: encoder id requesting for allocation
- * @reqs: proposed use case requirements
  * @lm: proposed layer mixer, function checks if lm, and all other hardwired
  *  blocks connected to the lm (pp) is available and appropriate
  * @pp: output parameter, pingpong block attached to the layer mixer.
@@ -305,7 +303,6 @@ static bool _dpu_rm_needs_split_display(const struct 
msm_display_topology *top)
 static bool _dpu_rm_check_lm_and_get_connected_blks(
struct dpu_rm *rm,
uint32_t enc_id,
-   struct dpu_rm_requirements *reqs,
struct dpu_rm_hw_blk *lm,
struct dpu_rm_hw_blk **pp,
struct dpu_rm_hw_blk *primary_lm)
@@ -384,7 +381,7 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, uint32_t 
enc_id,
lm[lm_count] = iter_i.blk;
 
if (!_dpu_rm_check_lm_and_get_connected_blks(
-   rm, enc_id, reqs, lm[lm_count],
+   rm, enc_id, lm[lm_count],
&pp[lm_count], NULL))
continue;
 
@@ -399,7 +396,7 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, uint32_t 
enc_id,
continue;
 
if (!_dpu_rm_check_lm_and_get_connected_blks(
-   rm, enc_id, reqs, iter_j.blk,
+   rm, enc_id, iter_j.blk,
&pp[lm_count], iter_i.blk))
continue;
 
@@ -480,20 +477,19 @@ static int _dpu_rm_reserve_ctls(
 static int _dpu_rm_reserve_intf(
struct dpu_rm *rm,
uint32_t enc_id,
-   uint32_t id,
-   enum dpu_hw_blk_type type)
+   uint32_t id)
 {
struct dpu_rm_hw_iter iter;
int ret = 0;
 
/* Find the block entry in the rm, and note the reservation */
-   dpu_rm_init_hw_iter(&iter, 0, type);
+   dpu_rm_init_hw_iter(&iter, 0, DPU_HW_BLK_INTF);
while (_dpu_rm_get_hw_locked(rm, &iter)) {
if (iter.blk->id != id)
continue;
 
if (RESERVED_BY_OTHER(iter.blk, enc_id)) {
-   DPU_ERROR("type %d id %d already reserved\n", type, id);
+   DPU_ERROR("intf id %d alr