Skip to content

Commit

Permalink
drm/imagination: Implement free list and HWRT create and destroy ioctls
Browse files Browse the repository at this point in the history
Implement ioctls to create and destroy free lists and HWRT datasets. Free
lists are used for GPU-side memory allocation during geometry processing.
HWRT datasets are the FW-side structures representing render targets.

Changes since v8:
- Corrected license identifiers

Changes since v6:
- Fix out-of-bounds shift in get_cr_multisamplectl_val()

Changes since v4:
- Remove use of drm_gem_shmem_get_pages()

Changes since v3:
- Support free list grow requests from FW
- Use drm_dev_{enter,exit}

Co-developed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Co-developed-by: Donald Robson <donald.robson@imgtec.com>
Signed-off-by: Donald Robson <donald.robson@imgtec.com>
Signed-off-by: Sarah Walker <sarah.walker@imgtec.com>
Link: https://lore.kernel.org/r/919358c5887a7628da588c455a5bb7e3ea4b47ae.1700668843.git.donald.robson@imgtec.com
Signed-off-by: Maxime Ripard <mripard@kernel.org>
  • Loading branch information
Sarah Walker authored and Maxime Ripard committed Nov 23, 2023
1 parent 927f3e0 commit 6eeddda
Show file tree
Hide file tree
Showing 8 changed files with 1,678 additions and 4 deletions.
2 changes: 2 additions & 0 deletions drivers/gpu/drm/imagination/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ powervr-y := \
pvr_device.o \
pvr_device_info.o \
pvr_drv.o \
pvr_free_list.o \
pvr_fw.o \
pvr_fw_meta.o \
pvr_fw_mips.o \
pvr_fw_startstop.o \
pvr_fw_trace.o \
pvr_gem.o \
pvr_hwrt.o \
pvr_mmu.o \
pvr_power.o \
pvr_vm.o \
Expand Down
10 changes: 10 additions & 0 deletions drivers/gpu/drm/imagination/pvr_ccb.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "pvr_ccb.h"
#include "pvr_device.h"
#include "pvr_drv.h"
#include "pvr_free_list.h"
#include "pvr_fw.h"
#include "pvr_gem.h"
#include "pvr_power.h"
Expand Down Expand Up @@ -139,6 +140,15 @@ process_fwccb_command(struct pvr_device *pvr_dev, struct rogue_fwif_fwccb_cmd *c
pvr_power_reset(pvr_dev, false);
break;

case ROGUE_FWIF_FWCCB_CMD_FREELISTS_RECONSTRUCTION:
pvr_free_list_process_reconstruct_req(pvr_dev,
&cmd->cmd_data.cmd_freelists_reconstruction);
break;

case ROGUE_FWIF_FWCCB_CMD_FREELIST_GROW:
pvr_free_list_process_grow_req(pvr_dev, &cmd->cmd_data.cmd_free_list_gs);
break;

default:
drm_info(from_pvr_device(pvr_dev), "Received unknown FWCCB command %x\n",
cmd->cmd_type);
Expand Down
24 changes: 24 additions & 0 deletions drivers/gpu/drm/imagination/pvr_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,14 @@ struct pvr_device {
*/
atomic_t mmu_flush_cache_flags;

/**
* @free_list_ids: Array of free lists belonging to this device. Array members
* are of type "struct pvr_free_list *".
*
* This array is used to allocate IDs used by the firmware.
*/
struct xarray free_list_ids;

struct {
/** @work: Work item for watchdog callback. */
struct delayed_work work;
Expand Down Expand Up @@ -247,6 +255,22 @@ struct pvr_file {
*/
struct pvr_device *pvr_dev;

/**
* @free_list_handles: Array of free lists belonging to this file. Array
* members are of type "struct pvr_free_list *".
*
* This array is used to allocate handles returned to userspace.
*/
struct xarray free_list_handles;

/**
* @hwrt_handles: Array of HWRT datasets belonging to this file. Array
* members are of type "struct pvr_hwrt_dataset *".
*
* This array is used to allocate handles returned to userspace.
*/
struct xarray hwrt_handles;

/**
* @vm_ctx_handles: Array of VM contexts belonging to this file. Array
* members are of type "struct pvr_vm_context *".
Expand Down
112 changes: 108 additions & 4 deletions drivers/gpu/drm/imagination/pvr_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

#include "pvr_device.h"
#include "pvr_drv.h"
#include "pvr_free_list.h"
#include "pvr_gem.h"
#include "pvr_hwrt.h"
#include "pvr_mmu.h"
#include "pvr_power.h"
#include "pvr_rogue_defs.h"
Expand Down Expand Up @@ -711,7 +713,41 @@ static int
pvr_ioctl_create_free_list(struct drm_device *drm_dev, void *raw_args,
struct drm_file *file)
{
return -ENOTTY;
struct drm_pvr_ioctl_create_free_list_args *args = raw_args;
struct pvr_file *pvr_file = to_pvr_file(file);
struct pvr_free_list *free_list;
int idx;
int err;

if (!drm_dev_enter(drm_dev, &idx))
return -EIO;

free_list = pvr_free_list_create(pvr_file, args);
if (IS_ERR(free_list)) {
err = PTR_ERR(free_list);
goto err_drm_dev_exit;
}

/* Allocate object handle for userspace. */
err = xa_alloc(&pvr_file->free_list_handles,
&args->handle,
free_list,
xa_limit_32b,
GFP_KERNEL);
if (err < 0)
goto err_cleanup;

drm_dev_exit(idx);

return 0;

err_cleanup:
pvr_free_list_put(free_list);

err_drm_dev_exit:
drm_dev_exit(idx);

return err;
}

/**
Expand All @@ -731,7 +767,19 @@ static int
pvr_ioctl_destroy_free_list(struct drm_device *drm_dev, void *raw_args,
struct drm_file *file)
{
return -ENOTTY;
struct drm_pvr_ioctl_destroy_free_list_args *args = raw_args;
struct pvr_file *pvr_file = to_pvr_file(file);
struct pvr_free_list *free_list;

if (args->_padding_4)
return -EINVAL;

free_list = xa_erase(&pvr_file->free_list_handles, args->handle);
if (!free_list)
return -EINVAL;

pvr_free_list_put(free_list);
return 0;
}

/**
Expand All @@ -751,7 +799,41 @@ static int
pvr_ioctl_create_hwrt_dataset(struct drm_device *drm_dev, void *raw_args,
struct drm_file *file)
{
return -ENOTTY;
struct drm_pvr_ioctl_create_hwrt_dataset_args *args = raw_args;
struct pvr_file *pvr_file = to_pvr_file(file);
struct pvr_hwrt_dataset *hwrt;
int idx;
int err;

if (!drm_dev_enter(drm_dev, &idx))
return -EIO;

hwrt = pvr_hwrt_dataset_create(pvr_file, args);
if (IS_ERR(hwrt)) {
err = PTR_ERR(hwrt);
goto err_drm_dev_exit;
}

/* Allocate object handle for userspace. */
err = xa_alloc(&pvr_file->hwrt_handles,
&args->handle,
hwrt,
xa_limit_32b,
GFP_KERNEL);
if (err < 0)
goto err_cleanup;

drm_dev_exit(idx);

return 0;

err_cleanup:
pvr_hwrt_dataset_put(hwrt);

err_drm_dev_exit:
drm_dev_exit(idx);

return err;
}

/**
Expand All @@ -771,7 +853,19 @@ static int
pvr_ioctl_destroy_hwrt_dataset(struct drm_device *drm_dev, void *raw_args,
struct drm_file *file)
{
return -ENOTTY;
struct drm_pvr_ioctl_destroy_hwrt_dataset_args *args = raw_args;
struct pvr_file *pvr_file = to_pvr_file(file);
struct pvr_hwrt_dataset *hwrt;

if (args->_padding_4)
return -EINVAL;

hwrt = xa_erase(&pvr_file->hwrt_handles, args->handle);
if (!hwrt)
return -EINVAL;

pvr_hwrt_dataset_put(hwrt);
return 0;
}

/**
Expand Down Expand Up @@ -1195,6 +1289,8 @@ pvr_drm_driver_open(struct drm_device *drm_dev, struct drm_file *file)
*/
pvr_file->pvr_dev = pvr_dev;

xa_init_flags(&pvr_file->free_list_handles, XA_FLAGS_ALLOC1);
xa_init_flags(&pvr_file->hwrt_handles, XA_FLAGS_ALLOC1);
xa_init_flags(&pvr_file->vm_ctx_handles, XA_FLAGS_ALLOC1);

/*
Expand Down Expand Up @@ -1223,6 +1319,8 @@ pvr_drm_driver_postclose(__always_unused struct drm_device *drm_dev,
struct pvr_file *pvr_file = to_pvr_file(file);

/* Drop references on any remaining objects. */
pvr_destroy_free_lists_for_file(pvr_file);
pvr_destroy_hwrt_datasets_for_file(pvr_file);
pvr_destroy_vm_contexts_for_file(pvr_file);

kfree(pvr_file);
Expand Down Expand Up @@ -1281,6 +1379,8 @@ pvr_probe(struct platform_device *plat_dev)
if (err)
goto err_device_fini;

xa_init_flags(&pvr_dev->free_list_ids, XA_FLAGS_ALLOC1);

return 0;

err_device_fini:
Expand All @@ -1298,6 +1398,10 @@ pvr_remove(struct platform_device *plat_dev)
struct drm_device *drm_dev = platform_get_drvdata(plat_dev);
struct pvr_device *pvr_dev = to_pvr_device(drm_dev);

WARN_ON(!xa_empty(&pvr_dev->free_list_ids));

xa_destroy(&pvr_dev->free_list_ids);

pm_runtime_suspend(drm_dev->dev);
pvr_device_fini(pvr_dev);
drm_dev_unplug(drm_dev);
Expand Down
Loading

0 comments on commit 6eeddda

Please sign in to comment.