Skip to content

Commit

Permalink
drm/panfrost: Implement per FD address spaces
Browse files Browse the repository at this point in the history
Up until now, a single shared GPU address space was used. This is not
ideal as there's no protection between processes and doesn't work for
supporting the same GPU/CPU VA feature. Most importantly, this will
hopefully mitigate Alyssa's fear of WebGL, whatever that is.

Most of the changes here are moving struct drm_mm and struct
panfrost_mmu objects from the per device struct to the per FD struct.
The critical function is panfrost_mmu_as_get() which handles allocating
and switching the h/w address spaces.

There's 3 states an AS can be in: free, allocated, and in use. When a
job runs, it requests an address space and then marks it not in use when
job is complete(but stays assigned). The first time thru, we find a free
AS in the alloc_mask and assign the AS to the FD. Then the next time
thru, we most likely already have our AS and we just mark it in use with
a ref count. We need a ref count because we have multiple job slots. If
the job/FD doesn't have an AS assigned and there are no free ones, then
we pick an allocated one not in use from our LRU list and switch the AS
from the old FD to the new one.

Cc: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Cc: David Airlie <airlied@linux.ie>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Steven Price <steven.price@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190813150115.30338-1-robh@kernel.org
  • Loading branch information
Rob Herring committed Aug 19, 2019
1 parent 3efdf83 commit 7282f76
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 87 deletions.
4 changes: 0 additions & 4 deletions drivers/gpu/drm/panfrost/TODO
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
- Bifrost specific feature and issue handling
- Coherent DMA support

- Per FD address space support. The h/w supports multiple addresses spaces.
The hard part is handling when more address spaces are needed than what
the h/w provides.

- Support userspace controlled GPU virtual addresses. Needed for Vulkan. (Tomeu)

- Compute job support. So called 'compute only' jobs need to be plumbed up to
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/panfrost/panfrost_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,10 @@ int panfrost_device_init(struct panfrost_device *pfdev)
mutex_init(&pfdev->sched_lock);
mutex_init(&pfdev->reset_lock);
INIT_LIST_HEAD(&pfdev->scheduled_jobs);
INIT_LIST_HEAD(&pfdev->as_lru_list);

spin_lock_init(&pfdev->hwaccess_lock);
spin_lock_init(&pfdev->as_lock);

err = panfrost_clk_init(pfdev);
if (err) {
Expand Down
24 changes: 20 additions & 4 deletions drivers/gpu/drm/panfrost/panfrost_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#ifndef __PANFROST_DEVICE_H__
#define __PANFROST_DEVICE_H__

#include <linux/atomic.h>
#include <linux/io-pgtable.h>
#include <linux/spinlock.h>
#include <drm/drm_device.h>
#include <drm/drm_mm.h>
Expand Down Expand Up @@ -63,9 +65,6 @@ struct panfrost_device {

spinlock_t hwaccess_lock;

struct drm_mm mm;
spinlock_t mm_lock;

void __iomem *iomem;
struct clk *clock;
struct clk *bus_clock;
Expand All @@ -74,7 +73,11 @@ struct panfrost_device {

struct panfrost_features features;

struct panfrost_mmu *mmu;
spinlock_t as_lock;
unsigned long as_in_use_mask;
unsigned long as_alloc_mask;
struct list_head as_lru_list;

struct panfrost_job_slot *js;

struct panfrost_job *jobs[NUM_JOB_SLOTS];
Expand All @@ -98,10 +101,23 @@ struct panfrost_device {
} devfreq;
};

struct panfrost_mmu {
struct io_pgtable_cfg pgtbl_cfg;
struct io_pgtable_ops *pgtbl_ops;
struct mutex lock;
int as;
atomic_t as_count;
struct list_head list;
};

struct panfrost_file_priv {
struct panfrost_device *pfdev;

struct drm_sched_entity sched_entity[NUM_JOB_SLOTS];

struct panfrost_mmu mmu;
struct drm_mm mm;
spinlock_t mm_lock;
};

static inline struct panfrost_device *to_panfrost_device(struct drm_device *ddev)
Expand Down
31 changes: 25 additions & 6 deletions drivers/gpu/drm/panfrost/panfrost_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ static void panfrost_drm_mm_color_adjust(const struct drm_mm_node *node,
static int
panfrost_open(struct drm_device *dev, struct drm_file *file)
{
int ret;
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_file_priv *panfrost_priv;

Expand All @@ -413,7 +414,28 @@ panfrost_open(struct drm_device *dev, struct drm_file *file)
panfrost_priv->pfdev = pfdev;
file->driver_priv = panfrost_priv;

return panfrost_job_open(panfrost_priv);
spin_lock_init(&panfrost_priv->mm_lock);

/* 4G enough for now. can be 48-bit */
drm_mm_init(&panfrost_priv->mm, SZ_32M >> PAGE_SHIFT, (SZ_4G - SZ_32M) >> PAGE_SHIFT);
panfrost_priv->mm.color_adjust = panfrost_drm_mm_color_adjust;

ret = panfrost_mmu_pgtable_alloc(panfrost_priv);
if (ret)
goto err_pgtable;

ret = panfrost_job_open(panfrost_priv);
if (ret)
goto err_job;

return 0;

err_job:
panfrost_mmu_pgtable_free(panfrost_priv);
err_pgtable:
drm_mm_takedown(&panfrost_priv->mm);
kfree(panfrost_priv);
return ret;
}

static void
Expand All @@ -424,6 +446,8 @@ panfrost_postclose(struct drm_device *dev, struct drm_file *file)
panfrost_perfcnt_close(panfrost_priv);
panfrost_job_close(panfrost_priv);

panfrost_mmu_pgtable_free(panfrost_priv);
drm_mm_takedown(&panfrost_priv->mm);
kfree(panfrost_priv);
}

Expand Down Expand Up @@ -496,14 +520,9 @@ static int panfrost_probe(struct platform_device *pdev)
ddev->dev_private = pfdev;
pfdev->ddev = ddev;

spin_lock_init(&pfdev->mm_lock);
mutex_init(&pfdev->shrinker_lock);
INIT_LIST_HEAD(&pfdev->shrinker_list);

/* 4G enough for now. can be 48-bit */
drm_mm_init(&pfdev->mm, SZ_32M >> PAGE_SHIFT, (SZ_4G - SZ_32M) >> PAGE_SHIFT);
pfdev->mm.color_adjust = panfrost_drm_mm_color_adjust;

pm_runtime_use_autosuspend(pfdev->dev);
pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */
pm_runtime_enable(pfdev->dev);
Expand Down
15 changes: 8 additions & 7 deletions drivers/gpu/drm/panfrost/panfrost_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ static int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_p
size_t size = obj->size;
u64 align;
struct panfrost_gem_object *bo = to_panfrost_bo(obj);
struct panfrost_device *pfdev = obj->dev->dev_private;
unsigned long color = bo->noexec ? PANFROST_BO_NOEXEC : 0;
struct panfrost_file_priv *priv = file_priv->driver_priv;

/*
* Executable buffers cannot cross a 16MB boundary as the program
Expand All @@ -61,8 +61,9 @@ static int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_p
else
align = size >= SZ_2M ? SZ_2M >> PAGE_SHIFT : 0;

spin_lock(&pfdev->mm_lock);
ret = drm_mm_insert_node_generic(&pfdev->mm, &bo->node,
bo->mmu = &priv->mmu;
spin_lock(&priv->mm_lock);
ret = drm_mm_insert_node_generic(&priv->mm, &bo->node,
size >> PAGE_SHIFT, align, color, 0);
if (ret)
goto out;
Expand All @@ -73,22 +74,22 @@ static int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_p
drm_mm_remove_node(&bo->node);
}
out:
spin_unlock(&pfdev->mm_lock);
spin_unlock(&priv->mm_lock);
return ret;
}

static void panfrost_gem_close(struct drm_gem_object *obj, struct drm_file *file_priv)
{
struct panfrost_gem_object *bo = to_panfrost_bo(obj);
struct panfrost_device *pfdev = obj->dev->dev_private;
struct panfrost_file_priv *priv = file_priv->driver_priv;

if (bo->is_mapped)
panfrost_mmu_unmap(bo);

spin_lock(&pfdev->mm_lock);
spin_lock(&priv->mm_lock);
if (drm_mm_node_allocated(&bo->node))
drm_mm_remove_node(&bo->node);
spin_unlock(&pfdev->mm_lock);
spin_unlock(&priv->mm_lock);
}

static int panfrost_gem_pin(struct drm_gem_object *obj)
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/panfrost/panfrost_gem.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_mm.h>

struct panfrost_mmu;

struct panfrost_gem_object {
struct drm_gem_shmem_object base;
struct sg_table *sgts;

struct panfrost_mmu *mmu;
struct drm_mm_node node;
bool is_mapped :1;
bool noexec :1;
Expand Down
14 changes: 10 additions & 4 deletions drivers/gpu/drm/panfrost/panfrost_job.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
if (WARN_ON(job_read(pfdev, JS_COMMAND_NEXT(js))))
goto end;

cfg = panfrost_mmu_as_get(pfdev, &job->file_priv->mmu);

panfrost_devfreq_record_transition(pfdev, js);
spin_lock_irqsave(&pfdev->hwaccess_lock, flags);

Expand All @@ -163,8 +165,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)

/* start MMU, medium priority, cache clean/flush on end, clean/flush on
* start */
/* TODO: different address spaces */
cfg = JS_CONFIG_THREAD_PRI(8) |
cfg |= JS_CONFIG_THREAD_PRI(8) |
JS_CONFIG_START_FLUSH_CLEAN_INVALIDATE |
JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE;

Expand Down Expand Up @@ -377,8 +378,9 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job)
if (dma_fence_is_signaled(job->done_fence))
return;

dev_err(pfdev->dev, "gpu sched timeout, js=%d, status=0x%x, head=0x%x, tail=0x%x, sched_job=%p",
dev_err(pfdev->dev, "gpu sched timeout, js=%d, config=0x%x, status=0x%x, head=0x%x, tail=0x%x, sched_job=%p",
js,
job_read(pfdev, JS_CONFIG(js)),
job_read(pfdev, JS_STATUS(js)),
job_read(pfdev, JS_HEAD_LO(js)),
job_read(pfdev, JS_TAIL_LO(js)),
Expand Down Expand Up @@ -448,8 +450,12 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
}

if (status & JOB_INT_MASK_DONE(j)) {
struct panfrost_job *job = pfdev->jobs[j];

pfdev->jobs[j] = NULL;
panfrost_mmu_as_put(pfdev, &job->file_priv->mmu);
panfrost_devfreq_record_transition(pfdev, j);
dma_fence_signal(pfdev->jobs[j]->done_fence);
dma_fence_signal(job->done_fence);
}

status &= ~mask;
Expand Down
Loading

0 comments on commit 7282f76

Please sign in to comment.