From nobody Fri Sep 20 19:35:31 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 747F2C7EE31 for ; Wed, 17 May 2023 14:53:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232201AbjEQOw7 (ORCPT ); Wed, 17 May 2023 10:52:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231740AbjEQOwx (ORCPT ); Wed, 17 May 2023 10:52:53 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E4A123A9C for ; Wed, 17 May 2023 07:52:46 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id ffacd0b85a97d-309438004a6so451840f8f.2 for ; Wed, 17 May 2023 07:52:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1684335165; x=1686927165; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=53yQ5WAlsgSKbKfPAJNRS0Vf8Mhg/M9EmPqqwDtVX7Y=; b=uP94VE8FRaeKi54S5wqD9ZoflKuQ97i4LxQN2rLaTlvpXkjiHzQZvTiILoc945VCvG EkvSyXfYBdYIbxrcK6Er6nXn9Rzhu53yIjnCpySHYihhSORMT2hkYMUNZZ8EBGzUlIsG jbbp5H2bZz2x/PTZpzW7GvEBJEClwCzasxSck2jBqjY8l8rWfMD2OQ7+ddDlM87K0vZZ AmBzb9YNhiP2MlNHEYbVnXbx0ZuTHT0qr+VdBkKYOCk6Z5SyxuvSH10wt7KxFYR9dB0X kyeu8l0gqKeO/If723w61vT9W8TFQvgaohDAscMVAslU/H4PFjpigrFC+5ffLqZI2xm5 465g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684335165; x=1686927165; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=53yQ5WAlsgSKbKfPAJNRS0Vf8Mhg/M9EmPqqwDtVX7Y=; b=elHEfRHMUUy5RQSRXaEY0gdM8pCS2rm7Zr9CLTXp8McttwS2ZPkxDR3juXOJDR4Iq6 67JnmH7NlPl7i129e2HkdJ2jKyFoFuKXvS0GjOUHeqyQKxEavGZjdqcpm6RoyBMaLprr SEDIi/z4Vv5E3kMUX5T8Azen8xxNO7iUnew6wuFKHDlbcV2BtUeNZat4jyhweO28pTkO W7O3y+0JTxn9KJShQ6SEEH1AtMCoW+Zaz0rg991B4h9CvczEgOZ6oFbTdgcolE2j9tqD 8/xdIvnw/oVC1Dr7d+Et0YJ8n0lnhQc/WGMvdi+LSpWP0pZdm1DShwacUxP/QSlhejs6 oPgw== X-Gm-Message-State: AC+VfDw1PfgOsBIIDzhRmer/aeGIFQpjvV2jZr+SmXe0wzdytsKOdnal vT6Hq6zqTRpS0p0WwBJulFMKkmiGMUvRaSzgUVtGqQ== X-Google-Smtp-Source: ACHHUZ7m6fs008rRX4GnYew3Bs5IbiZ+LTVWrGeG8VJEU+HTH+tD3errRQp3lrkI3GLvMjQRVqqLFA== X-Received: by 2002:a5d:591a:0:b0:309:3df3:8e0f with SMTP id v26-20020a5d591a000000b003093df38e0fmr997547wrd.51.1684335165200; Wed, 17 May 2023 07:52:45 -0700 (PDT) Received: from blaptop.baylibre (laubervilliers-658-1-213-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) by smtp.gmail.com with ESMTPSA id v11-20020a5d678b000000b002f7780eee10sm2979098wru.59.2023.05.17.07.52.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 07:52:44 -0700 (PDT) From: Alexandre Bailon To: airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, sumit.semwal@linaro.org, christian.koenig@amd.com, jstephan@baylibre.com, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, khilman@baylibre.com, nbelin@baylibre.com, bero@baylibre.com, Alexandre Bailon Subject: [PATCH 1/7] drm: Add support of AI Processor Unit (APU) Date: Wed, 17 May 2023 16:52:31 +0200 Message-Id: <20230517145237.295461-2-abailon@baylibre.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230517145237.295461-1-abailon@baylibre.com> References: <20230517145237.295461-1-abailon@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Many AI Processur Unit (APU) have a similar architecture. This driver intends helping supporting them. This relies on DRM and provides some abstractions useful for AI accelerators. Currently, this provides the infrastructure to alloc an APU device and register one or many cores. The driver will takes care to register itself to DRM. Signed-off-by: Alexandre Bailon Reviewed-by: Julien Stephan --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/apu/Kconfig | 12 ++ drivers/gpu/drm/apu/Makefile | 5 + drivers/gpu/drm/apu/apu_drv.c | 272 +++++++++++++++++++++++++++++ drivers/gpu/drm/apu/apu_internal.h | 68 ++++++++ include/uapi/drm/apu_drm.h | 28 +++ 7 files changed, 388 insertions(+) create mode 100644 drivers/gpu/drm/apu/Kconfig create mode 100644 drivers/gpu/drm/apu/Makefile create mode 100644 drivers/gpu/drm/apu/apu_drv.c create mode 100644 drivers/gpu/drm/apu/apu_internal.h create mode 100644 include/uapi/drm/apu_drm.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index ba3fb04bb691..32ffa66a8b54 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -371,6 +371,8 @@ source "drivers/gpu/drm/solomon/Kconfig" =20 source "drivers/gpu/drm/sprd/Kconfig" =20 +source "drivers/gpu/drm/apu/Kconfig" + config DRM_HYPERV tristate "DRM Support for Hyper-V synthetic video device" depends on DRM && PCI && MMU && HYPERV diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index a33257d2bc7f..7cd8c0f3936a 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -191,6 +191,7 @@ obj-$(CONFIG_DRM_MCDE) +=3D mcde/ obj-$(CONFIG_DRM_TIDSS) +=3D tidss/ obj-y +=3D xlnx/ obj-y +=3D gud/ +obj-$(CONFIG_DRM_APU) +=3D apu/ obj-$(CONFIG_DRM_HYPERV) +=3D hyperv/ obj-y +=3D solomon/ obj-$(CONFIG_DRM_SPRD) +=3D sprd/ diff --git a/drivers/gpu/drm/apu/Kconfig b/drivers/gpu/drm/apu/Kconfig new file mode 100644 index 000000000000..226dcf072115 --- /dev/null +++ b/drivers/gpu/drm/apu/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +# + +config DRM_APU + tristate "APU (AI Processor Unit)" + select DRM_GEM_DMA_HELPER + select DRM_KMS_HELPER + help + This provides a DRM driver that provides some facilities to + communicate with an AI Processor Unit (APU). + The driver intends to provide a common infrastructure that may be + used to support many different APU. diff --git a/drivers/gpu/drm/apu/Makefile b/drivers/gpu/drm/apu/Makefile new file mode 100644 index 000000000000..ad85b88a8b52 --- /dev/null +++ b/drivers/gpu/drm/apu/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +drm_apu-y +=3D apu_drv.o + +obj-$(CONFIG_DRM_APU) +=3D drm_apu.o diff --git a/drivers/gpu/drm/apu/apu_drv.c b/drivers/gpu/drm/apu/apu_drv.c new file mode 100644 index 000000000000..b420b13a9ffd --- /dev/null +++ b/drivers/gpu/drm/apu/apu_drv.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2020 BayLibre SAS + +#include +#include + +#include +#include +#include +#include + +#include "apu_internal.h" + +static LIST_HEAD(apu_devices); + +static int ioctl_apu_state(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +static const struct drm_ioctl_desc ioctls[] =3D { + DRM_IOCTL_DEF_DRV(APU_STATE, ioctl_apu_state, + DRM_RENDER_ALLOW), +}; + +DEFINE_DRM_GEM_DMA_FOPS(apu_drm_ops); + +static struct drm_driver apu_drm_driver =3D { + .driver_features =3D DRIVER_GEM | DRIVER_SYNCOBJ, + .name =3D "drm_apu", + .desc =3D "APU DRM driver", + .date =3D "20210319", + .major =3D 1, + .minor =3D 0, + .patchlevel =3D 0, + .ioctls =3D ioctls, + .num_ioctls =3D ARRAY_SIZE(ioctls), + .fops =3D &apu_drm_ops, + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(drm_gem_dma_dumb_create), +}; + +/** + * apu_dev_alloc() - Allocate a new APU device + * + * @dev: Pointer to the device instance. + + * This allocate an APU device. + * The APU describe a hardware accelerator that may have one or more + * core (or unit). + * + * Returns: A pointer or NULL in case of failure. + */ +struct apu_drm *apu_dev_alloc(struct device *dev) +{ + struct drm_device *drm; + struct apu_drm *apu; + + apu =3D devm_drm_dev_alloc(dev, &apu_drm_driver, typeof(*apu), base); + if (IS_ERR(apu)) + return NULL; + INIT_LIST_HEAD(&apu->cores); + + apu->dev =3D dev; + ida_init(&apu->ida); + drm =3D &apu->base; + drm->dev_private =3D apu; + + dev_set_drvdata(dev, drm); + + return apu; +} +EXPORT_SYMBOL_GPL(apu_dev_alloc); + +/** + * apu_dev_register() - Register the APU to DRM + * + * @apu: Pointer to APU device + * + * Register an APU device to DRM. + * On success, this creates everything required to use the APU. + * Note that at this step, the cores (or units) have not been + * registered so we can't yet perform any operations. + * + * Returns: Zero on success, non-zero value on failure. + */ +int apu_dev_register(struct apu_drm *apu) +{ + struct drm_device *drm =3D &apu->base; + int ret; + + ret =3D drm_dev_register(drm, 0); + if (ret) + return ret; + + list_add(&apu->node, &apu_devices); + + return 0; +} +EXPORT_SYMBOL_GPL(apu_dev_register); + +/** + * apu_dev_unregister() - Unregister the APU + * + * @apu: Pointer to APU device + * + * This undo what has been done by apu_dev_register(); + */ +void apu_dev_unregister(struct apu_drm *apu) +{ + struct drm_device *drm =3D &apu->base; + + list_del(&apu->node); + drm_dev_unregister(drm); +} +EXPORT_SYMBOL_GPL(apu_dev_unregister); + +/** + * apu_core_alloc() - Allocate an APU core + * + * @apu: Pointer to APU device + * @ops: The operation callbacks to use for this core + * @priv: + * + * Allocate an APU core. This represents a computing unit that could + * execute a job. The APU may be composed of different units that doesn't + * accept same kind of jobs so we may to use differents callbacks for each + * core. + * + * Returns: A pointer or NULL in case of failure. + */ +struct apu_core *apu_core_alloc(struct apu_drm *apu, struct apu_core_ops *= ops, + void *priv) +{ + struct apu_core *core; + + if (!ops || !ops->is_ready) + return NULL; + + core =3D devm_kzalloc(apu->dev, sizeof(*core), GFP_KERNEL); + if (!core) + return NULL; + + core->device_id =3D ida_alloc(&apu->ida, GFP_KERNEL); + if (core->device_id < 0) + return NULL; + + core->apu =3D apu; + core->priv =3D priv; + core->ops =3D ops; + + list_add(&core->node, &apu->cores); + + return core; +} +EXPORT_SYMBOL_GPL(apu_core_alloc); + +/** + * apu_core_free() - Free an APU core allocated using apu_core_alloc() + * + * @core: The APU core to release + */ +void apu_core_free(struct apu_core *core) +{ + ida_free(&core->apu->ida, core->device_id); + list_del(&core->node); +} +EXPORT_SYMBOL_GPL(apu_core_free); + +/** + * apu_core_register() - Register a core to APU device + * + * @dev: Pointer to APU device + * @core: Pointer to APU core to register + * @priv: Private data attached to this core + * + * Register an APU core and make it available for computing. + * On success, userspace can start using this core. + * + * Returns: Zero on success, non-zero value on failure. + */ +int apu_core_register(struct device *dev, struct apu_core *core, void *pri= v) +{ + int ret; + + core->dev_priv =3D priv; + core->dev =3D dev; + + if (core->ops->register_core) { + ret =3D core->ops->register_core(core); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(apu_core_register); + +/** + * apu_core_remove() - Remove a core from the APU device + * + * @core: Pointer to APU core to remove + */ +void apu_core_remove(struct apu_core *core) +{ + core->dev_priv =3D NULL; +} +EXPORT_SYMBOL_GPL(apu_core_remove); + +/** + * apu_find_core_by_priv() - Find a core allocated by apu_core_alloc() + * + * @priv: The pointer used to allocate the core + * + * All core allocated using apu_core_alloc() is registered to a list. + * This goes through the list to find the core using the @priv field. + * + * Returns: A pointer or NULL if no core has been found. + */ +struct apu_core *apu_find_core_by_priv(void *priv) +{ + struct apu_drm *apu; + struct apu_core *core; + + list_for_each_entry(apu, &apu_devices, node) { + list_for_each_entry(core, &apu->cores, node) { + if (core->priv =3D=3D priv) + return core; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(apu_find_core_by_priv); + +static struct apu_core *get_apu_core(struct apu_drm *apu, int device_id) +{ + struct apu_core *core; + + list_for_each_entry(core, &apu->cores, node) { + if (core->device_id =3D=3D device_id) + return core; + } + + return NULL; +} + +static void apu_core_update_state(struct apu_core *core) +{ + if (!core->ops->is_ready(core)) + core->flags &=3D ~APU_ONLINE; +} + +static int ioctl_apu_state(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct apu_drm *apu =3D dev->dev_private; + struct drm_apu_state *args =3D data; + struct apu_core *core; + + args->flags =3D 0; + + core =3D get_apu_core(apu, args->device); + if (!core) + return -ENODEV; + + apu_core_update_state(core); + args->flags |=3D core->flags; + + return 0; +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexandre Bailon"); diff --git a/drivers/gpu/drm/apu/apu_internal.h b/drivers/gpu/drm/apu/apu_i= nternal.h new file mode 100644 index 000000000000..58d93a16c68f --- /dev/null +++ b/drivers/gpu/drm/apu/apu_internal.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __APU_INTERNAL_H__ +#define __APU_INTERNAL_H__ + +#include + +struct apu_core { + int device_id; + struct device *dev; + struct apu_core_ops *ops; + struct apu_drm *apu; + + struct list_head node; + void *priv; + void *dev_priv; + + u32 flags; +}; + +struct apu_drm { + struct drm_device base; + struct device *dev; + + struct list_head cores; + struct list_head node; + + struct ida ida; +}; + +/** + * @apu_core_ops: Provides platform specific callbacks + */ +struct apu_core_ops { + /** + * @register_core: + * + * Optional. Platform specific APU core registration. + */ + int (*register_core)(struct apu_core *core); + + /** + * @is_ready: + * + * Implements platform specific code to test if APU is ready to receive + * commands. + * Basically, an APU core may be running but not be ready to handle + * commands. This allows checking if APU is ready and start executing + * requests. + * + * Returns: + * + * One if the APU is ready or zero. + */ + int (*is_ready)(struct apu_core *core); +}; + +struct apu_drm *apu_dev_alloc(struct device *dev); +int apu_dev_register(struct apu_drm *apu); +void apu_dev_unregister(struct apu_drm *apu); + +struct apu_core *apu_core_alloc(struct apu_drm *apu, struct apu_core_ops *= ops, + void *priv); +void apu_core_free(struct apu_core *core); +int apu_core_register(struct device *dev, struct apu_core *core, void *pri= v); +void apu_core_remove(struct apu_core *core); +struct apu_core *apu_find_core_by_priv(void *priv); + +#endif /* __APU_INTERNAL_H__ */ diff --git a/include/uapi/drm/apu_drm.h b/include/uapi/drm/apu_drm.h new file mode 100644 index 000000000000..d50c63d1b813 --- /dev/null +++ b/include/uapi/drm/apu_drm.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note*/ + +#ifndef __UAPI_APU_DRM_H__ +#define __UAPI_APU_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#define APU_ONLINE BIT(0) + +struct drm_apu_state { + __u32 device; + __u32 flags; +}; + +#define DRM_APU_STATE 0x00 +#define DRM_APU_NUM_IOCTLS 0x01 + +#define DRM_IOCTL_APU_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_STATE, st= ruct drm_apu_state) + +#if defined(__cplusplus) +} +#endif + +#endif /* __UAPI_APU_DRM_H__ */ --=20 2.39.2 From nobody Fri Sep 20 19:35:31 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E198DC7EE2A for ; Wed, 17 May 2023 14:52:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232202AbjEQOw5 (ORCPT ); Wed, 17 May 2023 10:52:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44710 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232034AbjEQOwx (ORCPT ); Wed, 17 May 2023 10:52:53 -0400 Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AE6665259 for ; Wed, 17 May 2023 07:52:47 -0700 (PDT) Received: by mail-wm1-x332.google.com with SMTP id 5b1f17b1804b1-3f4c6c4b425so6328285e9.2 for ; Wed, 17 May 2023 07:52:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1684335166; x=1686927166; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=6JUprTNR2AYUu5r4ykuSp6iVwLiXEOaF7GCdZkfyl4I=; b=mvPAtFy7apBepnb2BTkYGHlvdW8gzOsxkpjwMwkUvaUINN6vA6MJIgQbwok/QGlH8E hz+s2kr8iExnopHTUw8gL7llJFGaxST1HFeU3DvVO9ESvMAddRIW+HC3j7N42WTeU5kT uZD9jfR/Pe2bewmosqEXRDxYaOYyI6CGXVK8844+SddYPyX67Qpy6g+pAUY4J3rdMsrp NE77iiXnU8al++6TcHl6lxTCA1TFe9oGKXnNiQ/eVddXIdFIHf/md3w1N9dCAbRBrjXS xWnuZut8s3j43s0yWg5jT4VJgQRpIaO+nsd/OF++k3Rp0erxFbNkeiWQgiXorBrbFPE1 nEIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684335166; x=1686927166; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6JUprTNR2AYUu5r4ykuSp6iVwLiXEOaF7GCdZkfyl4I=; b=WLmKY+9BHn+hBMtBCpEJtkOZOL2T11xINfZH2GPvYRzoK7zfXdiXMxmj6Ver2PzIhC adrCfWlfPtXZP+SviUUAlcPY2ESkpmFjlYVFWK2m0qHGDysR+UKd5Vhyrt1wTsJfl1/j 6SYL4fQddUm6x9yNI2Q+oYSvfPM2NUBh1SKaDFIRfOS7bDR2xutCT3swT4R7d4NF959h q9aXZW7dW1Hfq0TMyxgC5UKByj8W9ylftbma7FkpOXaIH0x3YbGwhguY+vUhOOd24VVm ug8Ex/xr2lvgri7Uy2vTWXr03x3Nht09/3KlEdiPnflcuPbfy089F16IBPqvSvwDB0nu pplg== X-Gm-Message-State: AC+VfDxMKWEavCXPN42WbyIN7M28VNk4wzR65ofhPgW77FWZngfJUk3u gL+eLyICD8keUEWeBXCRlhi0Jg== X-Google-Smtp-Source: ACHHUZ7uV59fB+OW0baGaDbzIBdg1HfxU+jbrYxN5WEdFry9HrBC7HW5wsz8930CXaIqsQmv/54a7g== X-Received: by 2002:a1c:7c0f:0:b0:3f4:219f:5b7a with SMTP id x15-20020a1c7c0f000000b003f4219f5b7amr23742232wmc.30.1684335166168; Wed, 17 May 2023 07:52:46 -0700 (PDT) Received: from blaptop.baylibre (laubervilliers-658-1-213-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) by smtp.gmail.com with ESMTPSA id v11-20020a5d678b000000b002f7780eee10sm2979098wru.59.2023.05.17.07.52.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 07:52:45 -0700 (PDT) From: Alexandre Bailon To: airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, sumit.semwal@linaro.org, christian.koenig@amd.com, jstephan@baylibre.com, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, khilman@baylibre.com, nbelin@baylibre.com, bero@baylibre.com, Alexandre Bailon Subject: [PATCH 2/7] drm/apu: Add memory allocator Date: Wed, 17 May 2023 16:52:32 +0200 Message-Id: <20230517145237.295461-3-abailon@baylibre.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230517145237.295461-1-abailon@baylibre.com> References: <20230517145237.295461-1-abailon@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds a new ioctl to allocate GEM object. Signed-off-by: Alexandre Bailon Reviewed-by: Julien Stephan --- drivers/gpu/drm/apu/Makefile | 1 + drivers/gpu/drm/apu/apu_drv.c | 2 ++ drivers/gpu/drm/apu/apu_gem.c | 56 ++++++++++++++++++++++++++++++ drivers/gpu/drm/apu/apu_internal.h | 30 ++++++++++++++++ include/uapi/drm/apu_drm.h | 16 ++++++++- 5 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/apu/apu_gem.c diff --git a/drivers/gpu/drm/apu/Makefile b/drivers/gpu/drm/apu/Makefile index ad85b88a8b52..91894250d4c1 100644 --- a/drivers/gpu/drm/apu/Makefile +++ b/drivers/gpu/drm/apu/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 =20 drm_apu-y +=3D apu_drv.o +drm_apu-y +=3D apu_gem.o =20 obj-$(CONFIG_DRM_APU) +=3D drm_apu.o diff --git a/drivers/gpu/drm/apu/apu_drv.c b/drivers/gpu/drm/apu/apu_drv.c index b420b13a9ffd..323e267b0f53 100644 --- a/drivers/gpu/drm/apu/apu_drv.c +++ b/drivers/gpu/drm/apu/apu_drv.c @@ -20,6 +20,8 @@ static int ioctl_apu_state(struct drm_device *dev, void *= data, static const struct drm_ioctl_desc ioctls[] =3D { DRM_IOCTL_DEF_DRV(APU_STATE, ioctl_apu_state, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(APU_GEM_NEW, ioctl_gem_new, + DRM_RENDER_ALLOW), }; =20 DEFINE_DRM_GEM_DMA_FOPS(apu_drm_ops); diff --git a/drivers/gpu/drm/apu/apu_gem.c b/drivers/gpu/drm/apu/apu_gem.c new file mode 100644 index 000000000000..0e7b3b27942c --- /dev/null +++ b/drivers/gpu/drm/apu/apu_gem.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2020 BayLibre SAS + +#include + +#include + +#include "apu_internal.h" + +struct drm_gem_object *apu_gem_create_object(struct drm_device *dev, + size_t size) +{ + struct drm_gem_dma_object *dma_obj; + + dma_obj =3D drm_gem_dma_create(dev, size); + if (!dma_obj) + return NULL; + + return &dma_obj->base; +} + +int ioctl_gem_new(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_apu_gem_new *args =3D data; + struct drm_gem_dma_object *dma_obj; + struct apu_gem_object *apu_obj; + struct drm_gem_object *gem_obj; + int ret; + + dma_obj =3D drm_gem_dma_create(dev, args->size); + if (IS_ERR(dma_obj)) + return PTR_ERR(dma_obj); + + gem_obj =3D &dma_obj->base; + apu_obj =3D to_apu_bo(gem_obj); + + /* + * Save the size of buffer expected by application instead of the + * aligned one. + */ + apu_obj->size =3D args->size; + apu_obj->offset =3D 0; + mutex_init(&apu_obj->mutex); + + ret =3D drm_gem_handle_create(file_priv, gem_obj, &args->handle); + drm_gem_object_put(gem_obj); + if (ret) { + drm_gem_dma_object_free(gem_obj); + return ret; + } + args->offset =3D drm_vma_node_offset_addr(&gem_obj->vma_node); + + return 0; +} diff --git a/drivers/gpu/drm/apu/apu_internal.h b/drivers/gpu/drm/apu/apu_i= nternal.h index 58d93a16c68f..203aadc58b72 100644 --- a/drivers/gpu/drm/apu/apu_internal.h +++ b/drivers/gpu/drm/apu/apu_internal.h @@ -3,6 +3,14 @@ #define __APU_INTERNAL_H__ =20 #include +#include + +struct apu_gem_object { + struct drm_gem_dma_object base; + struct mutex mutex; + size_t size; + u32 offset; +}; =20 struct apu_core { int device_id; @@ -54,6 +62,17 @@ struct apu_core_ops { int (*is_ready)(struct apu_core *core); }; =20 +static inline struct apu_gem_object *to_apu_bo(struct drm_gem_object *obj) +{ + return container_of(to_drm_gem_dma_obj(obj), struct apu_gem_object, + base); +} + +static inline void *apu_drm_priv(struct apu_core *apu_core) +{ + return apu_core->dev_priv; +} + struct apu_drm *apu_dev_alloc(struct device *dev); int apu_dev_register(struct apu_drm *apu); void apu_dev_unregister(struct apu_drm *apu); @@ -65,4 +84,15 @@ int apu_core_register(struct device *dev, struct apu_cor= e *core, void *priv); void apu_core_remove(struct apu_core *core); struct apu_core *apu_find_core_by_priv(void *priv); =20 +struct apu_gem_object *to_apu_bo(struct drm_gem_object *obj); +struct drm_gem_object *apu_gem_create_object(struct drm_device *dev, + size_t size); + +int ioctl_gem_new(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int ioctl_gem_user_new(struct drm_device *dev, void *data, + struct drm_file *file_priv); +struct dma_buf *apu_gem_prime_export(struct drm_gem_object *gem, + int flags); + #endif /* __APU_INTERNAL_H__ */ diff --git a/include/uapi/drm/apu_drm.h b/include/uapi/drm/apu_drm.h index d50c63d1b813..14fc478f45dc 100644 --- a/include/uapi/drm/apu_drm.h +++ b/include/uapi/drm/apu_drm.h @@ -9,6 +9,18 @@ extern "C" { #endif =20 +/* + * Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + */ + +struct drm_apu_gem_new { + __u32 size; /* in */ + __u32 flags; /* in */ + __u32 handle; /* out */ + __u64 offset; /* out */ +}; + #define APU_ONLINE BIT(0) =20 struct drm_apu_state { @@ -17,9 +29,11 @@ struct drm_apu_state { }; =20 #define DRM_APU_STATE 0x00 -#define DRM_APU_NUM_IOCTLS 0x01 +#define DRM_APU_GEM_NEW 0x01 +#define DRM_APU_NUM_IOCTLS 0x02 =20 #define DRM_IOCTL_APU_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_STATE, st= ruct drm_apu_state) +#define DRM_IOCTL_APU_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_GEM_NEW= , struct drm_apu_gem_new) =20 #if defined(__cplusplus) } --=20 2.39.2 From nobody Fri Sep 20 19:35:31 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8BF63C77B75 for ; Wed, 17 May 2023 14:53:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232229AbjEQOxL (ORCPT ); Wed, 17 May 2023 10:53:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44734 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232197AbjEQOw4 (ORCPT ); Wed, 17 May 2023 10:52:56 -0400 Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 06159768C for ; Wed, 17 May 2023 07:52:48 -0700 (PDT) Received: by mail-wr1-x42f.google.com with SMTP id ffacd0b85a97d-3093a778089so629980f8f.1 for ; Wed, 17 May 2023 07:52:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1684335167; x=1686927167; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Nr7mrK+6tSYd8YQg8OUgoKT303dzmLPmQg+9F+7XGpw=; b=LzLDbCdcTBYtSEhd2l/0x+6iblcvk8LvzFbXOer3dStbScQfSb3AuwfX9ADL5SfoVx pNwu/FyIyTdKo5Y/nGSeJ6oIMO5SVb1fwjeTOz7WZH7dpFqcevDNsr7DO9F0ajlqtStV aOiDluo/V3mcJ3O294/tKHQOT4ksz4xkkM/+40IC0+wdldzn4e4TakwirwGaglzuMJiH wMd3cAteZqah/0CaQfSmGjvXbQgTga3WVxjUS4VtghXDsNIJWLb1azMix3Y5R9g/eaFv 2TqANN3iwPyqD7KktB4CknbHn25Gr+kQga/PRZkcemKLIZQJCn1YNt7smLzS4EeDy8IK E9dQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684335167; x=1686927167; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Nr7mrK+6tSYd8YQg8OUgoKT303dzmLPmQg+9F+7XGpw=; b=FFd0D/Pi6Pmy53hOIRccAcZH8ZCcHR64IYmEgmh2ElA9HLuBIEdH9CfjX6JJCBGlZO Niq9WlZpSZITCQuu5RmAZhryjvWzEVEXpSuIDP0nrs3qU4NYRnc53qTZfD4kAfH7gzJN AMN2iiyk+/ggTkRztY6OoM5Jvu8G/tEAa6aLXxT4+x+ecH0SBZlhmAAIX1FCoqc/YbIx pMMdvd4mhlZpaTdi6HM+Jw8oXphghqi9j6BxlaHbLBm23Vhvs4Vl1pfrCYxvoKQ3LZ8P 5yNDRIN7fV0ZCY6mKJjze6TMirjueNBVHtI2PbdgGr4XEK4lpn6hytwaAm2ss/cPyZLr kH0A== X-Gm-Message-State: AC+VfDyqJkorIuT4UUi01bjVqgJBcW4Op1FO3KsCEVjTAG+d4AW5+g2q zEyQnmWLAYmeBOx5cMNSAdT2Eg== X-Google-Smtp-Source: ACHHUZ6E9PDxwNASjWneyPfqsNbUMzas8Fc4Vnk/HvhbHQcmj7121Shzz9bplamcC/BeRNWcybflUw== X-Received: by 2002:a5d:63c3:0:b0:306:321c:995b with SMTP id c3-20020a5d63c3000000b00306321c995bmr966382wrw.41.1684335167157; Wed, 17 May 2023 07:52:47 -0700 (PDT) Received: from blaptop.baylibre (laubervilliers-658-1-213-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) by smtp.gmail.com with ESMTPSA id v11-20020a5d678b000000b002f7780eee10sm2979098wru.59.2023.05.17.07.52.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 07:52:46 -0700 (PDT) From: Alexandre Bailon To: airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, sumit.semwal@linaro.org, christian.koenig@amd.com, jstephan@baylibre.com, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, khilman@baylibre.com, nbelin@baylibre.com, bero@baylibre.com, Alexandre Bailon Subject: [PATCH 3/7] drm/apu: Add support of requests Date: Wed, 17 May 2023 16:52:33 +0200 Message-Id: <20230517145237.295461-4-abailon@baylibre.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230517145237.295461-1-abailon@baylibre.com> References: <20230517145237.295461-1-abailon@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This updates the APU driver to with two new ioctls to queue and dequeue requests. This uses DRM scheduler to manage the requests. The requests allocation and send and receive operations are platform specifics and must be implemented as callback. Signed-off-by: Alexandre Bailon Reviewed-by: Julien Stephan --- drivers/gpu/drm/apu/Kconfig | 1 + drivers/gpu/drm/apu/Makefile | 1 + drivers/gpu/drm/apu/apu_drv.c | 52 +-- drivers/gpu/drm/apu/apu_internal.h | 93 ++++- drivers/gpu/drm/apu/apu_sched.c | 564 +++++++++++++++++++++++++++++ include/uapi/drm/apu_drm.h | 31 +- 6 files changed, 697 insertions(+), 45 deletions(-) create mode 100644 drivers/gpu/drm/apu/apu_sched.c diff --git a/drivers/gpu/drm/apu/Kconfig b/drivers/gpu/drm/apu/Kconfig index 226dcf072115..a769df42091c 100644 --- a/drivers/gpu/drm/apu/Kconfig +++ b/drivers/gpu/drm/apu/Kconfig @@ -5,6 +5,7 @@ config DRM_APU tristate "APU (AI Processor Unit)" select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER + select DRM_SCHED help This provides a DRM driver that provides some facilities to communicate with an AI Processor Unit (APU). diff --git a/drivers/gpu/drm/apu/Makefile b/drivers/gpu/drm/apu/Makefile index 91894250d4c1..fc8d6380fc38 100644 --- a/drivers/gpu/drm/apu/Makefile +++ b/drivers/gpu/drm/apu/Makefile @@ -2,5 +2,6 @@ =20 drm_apu-y +=3D apu_drv.o drm_apu-y +=3D apu_gem.o +drm_apu-y +=3D apu_sched.o =20 obj-$(CONFIG_DRM_APU) +=3D drm_apu.o diff --git a/drivers/gpu/drm/apu/apu_drv.c b/drivers/gpu/drm/apu/apu_drv.c index 323e267b0f53..b6bd340b2bc8 100644 --- a/drivers/gpu/drm/apu/apu_drv.c +++ b/drivers/gpu/drm/apu/apu_drv.c @@ -14,14 +14,15 @@ =20 static LIST_HEAD(apu_devices); =20 -static int ioctl_apu_state(struct drm_device *dev, void *data, - struct drm_file *file_priv); - static const struct drm_ioctl_desc ioctls[] =3D { DRM_IOCTL_DEF_DRV(APU_STATE, ioctl_apu_state, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(APU_GEM_NEW, ioctl_gem_new, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(APU_GEM_QUEUE, ioctl_gem_queue, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(APU_GEM_DEQUEUE, ioctl_gem_dequeue, + DRM_RENDER_ALLOW), }; =20 DEFINE_DRM_GEM_DMA_FOPS(apu_drm_ops); @@ -134,7 +135,8 @@ struct apu_core *apu_core_alloc(struct apu_drm *apu, st= ruct apu_core_ops *ops, { struct apu_core *core; =20 - if (!ops || !ops->is_ready) + if (!ops || !ops->alloc_prepare_request || !ops->send_request + || !ops->handle_request || !ops->is_ready) return NULL; =20 core =3D devm_kzalloc(apu->dev, sizeof(*core), GFP_KERNEL); @@ -148,6 +150,8 @@ struct apu_core *apu_core_alloc(struct apu_drm *apu, st= ruct apu_core_ops *ops, core->apu =3D apu; core->priv =3D priv; core->ops =3D ops; + spin_lock_init(&core->ctx_lock); + INIT_LIST_HEAD(&core->requests); =20 list_add(&core->node, &apu->cores); =20 @@ -192,7 +196,7 @@ int apu_core_register(struct device *dev, struct apu_co= re *core, void *priv) return ret; } =20 - return 0; + return apu_drm_job_init(core); } EXPORT_SYMBOL_GPL(apu_core_register); =20 @@ -203,6 +207,7 @@ EXPORT_SYMBOL_GPL(apu_core_register); */ void apu_core_remove(struct apu_core *core) { + apu_sched_fini(core); core->dev_priv =3D NULL; } EXPORT_SYMBOL_GPL(apu_core_remove); @@ -233,42 +238,5 @@ struct apu_core *apu_find_core_by_priv(void *priv) } EXPORT_SYMBOL_GPL(apu_find_core_by_priv); =20 -static struct apu_core *get_apu_core(struct apu_drm *apu, int device_id) -{ - struct apu_core *core; - - list_for_each_entry(core, &apu->cores, node) { - if (core->device_id =3D=3D device_id) - return core; - } - - return NULL; -} - -static void apu_core_update_state(struct apu_core *core) -{ - if (!core->ops->is_ready(core)) - core->flags &=3D ~APU_ONLINE; -} - -static int ioctl_apu_state(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct apu_drm *apu =3D dev->dev_private; - struct drm_apu_state *args =3D data; - struct apu_core *core; - - args->flags =3D 0; - - core =3D get_apu_core(apu, args->device); - if (!core) - return -ENODEV; - - apu_core_update_state(core); - args->flags |=3D core->flags; - - return 0; -} - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexandre Bailon"); diff --git a/drivers/gpu/drm/apu/apu_internal.h b/drivers/gpu/drm/apu/apu_i= nternal.h index 203aadc58b72..021a3efdedf2 100644 --- a/drivers/gpu/drm/apu/apu_internal.h +++ b/drivers/gpu/drm/apu/apu_internal.h @@ -4,6 +4,7 @@ =20 #include #include +#include =20 struct apu_gem_object { struct drm_gem_dma_object base; @@ -12,16 +13,21 @@ struct apu_gem_object { u32 offset; }; =20 +struct apu_sched; struct apu_core { int device_id; struct device *dev; struct apu_core_ops *ops; struct apu_drm *apu; =20 + spinlock_t ctx_lock; + struct list_head requests; + struct list_head node; void *priv; void *dev_priv; =20 + struct apu_sched *sched; u32 flags; }; =20 @@ -35,6 +41,43 @@ struct apu_drm { struct ida ida; }; =20 +struct apu_job { + struct drm_sched_job base; + + struct kref refcount; + + struct apu_core *core; + struct apu_drm *apu; + + /* Fence to be signaled by IRQ handler when the job is complete. */ + struct dma_fence *done_fence; + + __u32 cmd; + + /* Exclusive fences we have taken from the BOs to wait for */ + struct dma_fence **implicit_fences; + struct drm_gem_object **bos; + u32 bo_count; + + /* Fence to be signaled by drm-sched once its done with the job */ + struct dma_fence *render_done_fence; + + void *data_in; + uint16_t size_in; + void *data_out; + uint16_t size_out; + uint16_t result; + uint16_t id; + + struct list_head node; + struct drm_syncobj *sync_out; + + struct apu_event *event; + + void *request_data; + int request_len; +}; + /** * @apu_core_ops: Provides platform specific callbacks */ @@ -46,6 +89,40 @@ struct apu_core_ops { */ int (*register_core)(struct apu_core *core); =20 + /** + * @alloc_prepare_request: + * + * Allocate and initialize the data to be sent to the APU. + * Basically, this must convert the job object to something + * that could be understand by the hardware accelerator. + * + * Returns: + * + * Zero on success, non-zero value on failure. + */ + int (*alloc_prepare_request)(struct apu_job *job); + + /** + * @send_data: + * + * Implements platform specific code to send the data previously + * allocated using @alloc_data. + * + * Returns: + * + * Zero on success, non-zero value on failure. + */ + int (*send_request)(struct apu_job *job); + + /** + * @handle_request: + * + * Implements platform specific code to handle incoming request. + * This must decode the data encoded using platform specific format + * and convert it to generic format. + */ + int (*handle_request)(struct apu_job *job, void *data, int len); + /** * @is_ready: * @@ -68,9 +145,9 @@ static inline struct apu_gem_object *to_apu_bo(struct dr= m_gem_object *obj) base); } =20 -static inline void *apu_drm_priv(struct apu_core *apu_core) +static inline void *apu_drm_priv(struct apu_core *core) { - return apu_core->dev_priv; + return core->dev_priv; } =20 struct apu_drm *apu_dev_alloc(struct device *dev); @@ -94,5 +171,17 @@ int ioctl_gem_user_new(struct drm_device *dev, void *da= ta, struct drm_file *file_priv); struct dma_buf *apu_gem_prime_export(struct drm_gem_object *gem, int flags); +int ioctl_gem_queue(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int ioctl_gem_dequeue(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int ioctl_apu_state(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int apu_drm_callback(struct apu_core *core, uint16_t job_id, void *data, i= nt len); + +struct apu_job; + +int apu_drm_job_init(struct apu_core *core); +void apu_sched_fini(struct apu_core *core); =20 #endif /* __APU_INTERNAL_H__ */ diff --git a/drivers/gpu/drm/apu/apu_sched.c b/drivers/gpu/drm/apu/apu_sche= d.c new file mode 100644 index 000000000000..13b6fbd00bd8 --- /dev/null +++ b/drivers/gpu/drm/apu/apu_sched.c @@ -0,0 +1,564 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2020 BayLibre SAS + +#include +#include +#include + +#include "apu_internal.h" + +struct apu_queue_state { + struct drm_gpu_scheduler sched; + u64 fence_context; + u64 seqno; +}; + +struct apu_request { + struct list_head node; + struct apu_job *job; +}; + +struct apu_sched { + struct apu_queue_state apu_queue; + spinlock_t job_lock; + struct drm_sched_entity sched_entity; +}; + +struct apu_event { + struct drm_pending_event pending_event; + union { + struct drm_event base; + struct apu_job_event job_event; + }; +}; + +static DEFINE_IDA(req_ida); +static LIST_HEAD(complete_node); + +static void apu_core_update_state(struct apu_core *core) +{ + if (!core->ops->is_ready(core)) + core->flags &=3D ~APU_ONLINE; +} + +static int apu_core_is_running(struct apu_core *core) +{ + apu_core_update_state(core); + + return core->flags & APU_ONLINE; +} + +static void apu_set_online(struct apu_core *core) +{ + core->flags |=3D APU_ONLINE; +} + +static void apu_set_offline(struct apu_core *core) +{ + core->flags &=3D ~APU_ONLINE; +} + +/* + * apu_drm_callback() - Handle the data coming from accelerator + * + * @core: The pointer to the APU core + * @job_id: The job id + * @data: The data coming from the accelerator + * @len: The size of the data + * + * Returns: Zero on success, non-zero value on failure. + */ +int apu_drm_callback(struct apu_core *core, uint16_t job_id, void *data, i= nt len) +{ + struct apu_request *apu_req, *tmp; + unsigned long flags; + int ret =3D -EINVAL; + + spin_lock_irqsave(&core->ctx_lock, flags); + list_for_each_entry_safe(apu_req, tmp, &core->requests, node) { + struct apu_job *job =3D apu_req->job; + + if (job && job_id =3D=3D job->id) { + kref_get(&job->refcount); + ret =3D core->ops->handle_request(job, data, len); + list_add(&job->node, &complete_node); + list_del(&apu_req->node); + ida_simple_remove(&req_ida, job->id); + kfree(apu_req); + drm_send_event(&job->apu->base, + &job->event->pending_event); + dma_fence_signal_locked(job->done_fence); + break; + } + } + spin_unlock_irqrestore(&core->ctx_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(apu_drm_callback); + +static void apu_job_cleanup(struct kref *ref) +{ + struct apu_job *job =3D container_of(ref, struct apu_job, + refcount); + unsigned int i; + + if (job->implicit_fences) { + for (i =3D 0; i < job->bo_count; i++) + dma_fence_put(job->implicit_fences[i]); + kvfree(job->implicit_fences); + } + dma_fence_put(job->done_fence); + dma_fence_put(job->render_done_fence); + + if (job->bos) { + for (i =3D 0; i < job->bo_count; i++) { + struct apu_gem_object *apu_obj; + + apu_obj =3D to_apu_bo(job->bos[i]); + drm_gem_object_put(job->bos[i]); + } + + kvfree(job->bos); + } + + kfree(job->data_out); + kfree(job->data_in); + kfree(job); +} + +static void apu_job_put(struct apu_job *job) +{ + kref_put(&job->refcount, apu_job_cleanup); +} + +static void apu_acquire_object_fences(struct drm_gem_object **bos, + int bo_count, + struct dma_fence **implicit_fences) +{ + int i; + + for (i =3D 0; i < bo_count; i++) + dma_resv_get_singleton(bos[i]->resv, DMA_RESV_USAGE_KERNEL, + &implicit_fences[i]); +} + +static void apu_attach_object_fences(struct drm_gem_object **bos, + int bo_count, struct dma_fence *fence) +{ + int i; + + for (i =3D 0; i < bo_count; i++) { + dma_resv_reserve_fences(bos[i]->resv, 1); + dma_resv_add_fence(bos[i]->resv, fence, DMA_RESV_USAGE_KERNEL); + } +} + +static int apu_job_push(struct apu_job *job) +{ + struct drm_sched_entity *entity =3D &job->core->sched->sched_entity; + struct ww_acquire_ctx acquire_ctx; + int ret =3D 0; + int i; + + ret =3D drm_gem_lock_reservations(job->bos, job->bo_count, &acquire_ctx); + if (ret) + return ret; + + ret =3D drm_sched_job_init(&job->base, entity, NULL); + if (ret) + goto unlock; + + drm_sched_job_arm(&job->base); + job->render_done_fence =3D dma_fence_get(&job->base.s_fence->finished); + + kref_get(&job->refcount); /* put by scheduler job completion */ + apu_acquire_object_fences(job->bos, job->bo_count, + job->implicit_fences); + + drm_sched_entity_push_job(&job->base); + + apu_attach_object_fences(job->bos, job->bo_count, + job->render_done_fence); + + for (i =3D 0; i < job->bo_count; i++) + ret =3D drm_sched_job_add_implicit_dependencies(&job->base, job->bos[i], + true); +unlock: + drm_gem_unlock_reservations(job->bos, job->bo_count, &acquire_ctx); + + return ret; +} + +static const char *apu_fence_get_driver_name(struct dma_fence *fence) +{ + return "apu"; +} + +static const char *apu_fence_get_timeline_name(struct dma_fence *fence) +{ + return "apu-0"; +} + +static void apu_fence_release(struct dma_fence *f) +{ + kfree(f); +} + +static const struct dma_fence_ops apu_fence_ops =3D { + .get_driver_name =3D apu_fence_get_driver_name, + .get_timeline_name =3D apu_fence_get_timeline_name, + .release =3D apu_fence_release, +}; + +static struct dma_fence *apu_fence_create(struct apu_sched *sched) +{ + struct dma_fence *fence; + struct apu_queue_state *apu_queue =3D &sched->apu_queue; + + fence =3D kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return ERR_PTR(-ENOMEM); + + dma_fence_init(fence, &apu_fence_ops, &sched->job_lock, + apu_queue->fence_context, apu_queue->seqno++); + + return fence; +} + +static struct apu_job *to_apu_job(struct drm_sched_job *sched_job) +{ + return container_of(sched_job, struct apu_job, base); +} + +static int apu_job_hw_submit(struct apu_job *job) +{ + int ret; + struct apu_core *core =3D job->core; + struct apu_request *apu_req; + unsigned long flags; + + ret =3D ida_simple_get(&req_ida, 0, 0xffff, GFP_KERNEL); + if (ret < 0) + return ret; + job->id =3D ret; + + ret =3D core->ops->alloc_prepare_request(job); + if (ret || !job->request_data || !job->request_len) { + ret =3D -ENOMEM; + goto err_ida_remove; + } + + apu_req =3D kzalloc(sizeof(*apu_req), GFP_KERNEL); + if (!apu_req) { + ret =3D -ENOMEM; + goto err_free_data; + } + + apu_req->job =3D job; + spin_lock_irqsave(&core->ctx_lock, flags); + list_add(&apu_req->node, &core->requests); + spin_unlock_irqrestore(&core->ctx_lock, flags); + ret =3D core->ops->send_request(job); + if (ret < 0) + goto err; + kfree(job->request_data); + + return 0; + +err: + list_del(&apu_req->node); + kfree(apu_req); +err_free_data: + kfree(job->request_data); +err_ida_remove: + ida_simple_remove(&req_ida, job->id); + + return ret; +} + +static struct dma_fence *apu_job_run(struct drm_sched_job *sched_job) +{ + struct apu_job *job =3D to_apu_job(sched_job); + struct dma_fence *fence =3D NULL; + + if (unlikely(job->base.s_fence->finished.error)) + return NULL; + + fence =3D apu_fence_create(job->core->sched); + if (IS_ERR(fence)) + return NULL; + + job->done_fence =3D dma_fence_get(fence); + + apu_job_hw_submit(job); + + return fence; +} + +static enum drm_gpu_sched_stat apu_job_timedout(struct drm_sched_job *sche= d_job) +{ + struct apu_request *apu_req, *tmp; + struct apu_job *job =3D to_apu_job(sched_job); + + if (dma_fence_is_signaled(job->done_fence)) + return DRM_GPU_SCHED_STAT_NOMINAL; + + list_for_each_entry_safe(apu_req, tmp, &job->core->requests, node) { + /* Remove the request and notify user about timeout */ + if (apu_req->job =3D=3D job) { + kref_get(&job->refcount); + job->result =3D ETIMEDOUT; + list_add(&job->node, &complete_node); + list_del(&apu_req->node); + ida_simple_remove(&req_ida, job->id); + kfree(apu_req); + drm_send_event(&job->apu->base, + &job->event->pending_event); + dma_fence_signal_locked(job->done_fence); + } + } + + return DRM_GPU_SCHED_STAT_NOMINAL; +} + +static void apu_job_free(struct drm_sched_job *sched_job) +{ + struct apu_job *job =3D to_apu_job(sched_job); + + drm_sched_job_cleanup(sched_job); + + apu_job_put(job); +} + +static const struct drm_sched_backend_ops apu_sched_ops =3D { + .run_job =3D apu_job_run, + .timedout_job =3D apu_job_timedout, + .free_job =3D apu_job_free +}; + +int apu_drm_job_init(struct apu_core *core) +{ + int ret; + struct apu_sched *apu_sched; + struct drm_gpu_scheduler *sched; + + apu_sched =3D devm_kzalloc(core->dev, sizeof(*apu_sched), GFP_KERNEL); + if (!apu_sched) + return -ENOMEM; + + sched =3D &apu_sched->apu_queue.sched; + apu_sched->apu_queue.fence_context =3D dma_fence_context_alloc(1); + ret =3D drm_sched_init(sched, &apu_sched_ops, + 1, 0, msecs_to_jiffies(500), + NULL, NULL, "apu_js", core->dev); + if (ret) { + dev_err(core->dev, "Failed to create scheduler"); + return ret; + } + + ret =3D drm_sched_entity_init(&apu_sched->sched_entity, + DRM_SCHED_PRIORITY_NORMAL, + &sched, 1, NULL); + if (ret) { + dev_err(core->dev, "Failed to initialize scheduler entity"); + drm_sched_fini(&core->sched->apu_queue.sched); + return ret; + } + + core->sched =3D apu_sched; + apu_set_online(core); + + return 0; +} + +void apu_sched_fini(struct apu_core *core) +{ + apu_set_offline(core); + drm_sched_fini(&core->sched->apu_queue.sched); + devm_kfree(core->dev, core->sched); + core->sched =3D NULL; +} + +static struct apu_core *get_apu_core(struct apu_drm *apu, int device_id) +{ + struct apu_core *core; + + list_for_each_entry(core, &apu->cores, node) { + if (core->device_id =3D=3D device_id) + return core; + } + + return NULL; +} + +static int apu_lookup_bos(struct drm_device *dev, struct drm_file *file_pr= iv, + struct drm_apu_gem_queue *args, struct apu_job *job) +{ + void __user *bo_handles; + int ret; + + job->bo_count =3D args->bo_handle_count; + + if (!job->bo_count) + return 0; + + job->implicit_fences =3D kvmalloc_array(job->bo_count, + sizeof(struct dma_fence *), + GFP_KERNEL | __GFP_ZERO); + if (!job->implicit_fences) + return -ENOMEM; + + bo_handles =3D (void __user *)(uintptr_t) args->bo_handles; + ret =3D drm_gem_objects_lookup(file_priv, bo_handles, + job->bo_count, &job->bos); + + return ret; +} + +int ioctl_gem_queue(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct apu_drm *apu =3D dev->dev_private; + struct drm_apu_gem_queue *args =3D data; + struct apu_event *event; + struct apu_core *core; + struct drm_syncobj *sync_out =3D NULL; + struct apu_job *job; + int ret =3D 0; + + core =3D get_apu_core(apu, args->device); + if (!apu_core_is_running(core)) + return -ENODEV; + + if (args->out_sync > 0) { + sync_out =3D drm_syncobj_find(file_priv, args->out_sync); + if (!sync_out) + return -ENODEV; + } + + job =3D kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) { + ret =3D -ENOMEM; + goto fail_out_sync; + } + + kref_init(&job->refcount); + + job->apu =3D apu; + job->core =3D core; + job->cmd =3D args->cmd; + job->size_in =3D args->size_in; + job->size_out =3D args->size_out; + job->sync_out =3D sync_out; + if (job->size_in) { + job->data_in =3D kmalloc(job->size_in, GFP_KERNEL); + if (!job->data_in) { + ret =3D -ENOMEM; + goto fail_job; + } + + ret =3D + copy_from_user(job->data_in, + (void __user *)(uintptr_t) args->data, + job->size_in); + if (ret) + goto fail_job; + } + + if (job->size_out) { + job->data_out =3D kmalloc(job->size_out, GFP_KERNEL); + if (!job->data_out) { + ret =3D -ENOMEM; + goto fail_job; + } + } + + ret =3D apu_lookup_bos(dev, file_priv, args, job); + if (ret) + goto fail_job; + + event =3D kzalloc(sizeof(*event), GFP_KERNEL); + event->base.length =3D sizeof(struct apu_job_event); + event->base.type =3D APU_JOB_COMPLETED; + event->job_event.out_sync =3D args->out_sync; + job->event =3D event; + ret =3D drm_event_reserve_init(dev, file_priv, &job->event->pending_event, + &job->event->base); + if (ret) + goto fail_job; + + ret =3D apu_job_push(job); + if (ret) { + drm_event_cancel_free(dev, &job->event->pending_event); + goto fail_job; + } + + if (sync_out) + drm_syncobj_replace_fence(sync_out, job->render_done_fence); + +fail_job: + apu_job_put(job); +fail_out_sync: + if (sync_out) + drm_syncobj_put(sync_out); + + return ret; +} + +int ioctl_gem_dequeue(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_apu_gem_dequeue *args =3D data; + struct drm_syncobj *sync_out =3D NULL; + struct apu_job *job; + int ret =3D 0; + + if (args->out_sync > 0) { + sync_out =3D drm_syncobj_find(file_priv, args->out_sync); + if (!sync_out) + return -ENODEV; + } + + list_for_each_entry(job, &complete_node, node) { + if (job->sync_out =3D=3D sync_out) { + if (job->data_out) { + ret =3D copy_to_user((void __user *)(uintptr_t) + args->data, job->data_out, + job->size_out); + args->size =3D job->size_out; + } + args->result =3D job->result; + list_del(&job->node); + apu_job_put(job); + drm_syncobj_put(sync_out); + + return ret; + } + } + + if (sync_out) + drm_syncobj_put(sync_out); + + return 0; +} + +int ioctl_apu_state(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct apu_drm *apu =3D dev->dev_private; + struct drm_apu_state *args =3D data; + struct apu_core *core; + + args->flags =3D 0; + + core =3D get_apu_core(apu, args->device); + if (!core) + return -ENODEV; + + apu_core_update_state(core); + args->flags |=3D core->flags; + + return 0; +} diff --git a/include/uapi/drm/apu_drm.h b/include/uapi/drm/apu_drm.h index 14fc478f45dc..c47000097040 100644 --- a/include/uapi/drm/apu_drm.h +++ b/include/uapi/drm/apu_drm.h @@ -9,6 +9,8 @@ extern "C" { #endif =20 +#define APU_JOB_COMPLETED 0x80000000 + /* * Please note that modifications to all structs defined here are * subject to backwards-compatibility constraints. @@ -21,6 +23,29 @@ struct drm_apu_gem_new { __u64 offset; /* out */ }; =20 +struct drm_apu_gem_queue { + __u32 device; + __u32 cmd; + __u32 out_sync; + __u64 bo_handles; + __u32 bo_handle_count; + __u16 size_in; + __u16 size_out; + __u64 data; +}; + +struct drm_apu_gem_dequeue { + __u32 out_sync; + __u16 result; + __u16 size; + __u64 data; +}; + +struct apu_job_event { + struct drm_event base; + __u32 out_sync; +}; + #define APU_ONLINE BIT(0) =20 struct drm_apu_state { @@ -30,10 +55,14 @@ struct drm_apu_state { =20 #define DRM_APU_STATE 0x00 #define DRM_APU_GEM_NEW 0x01 -#define DRM_APU_NUM_IOCTLS 0x02 +#define DRM_APU_GEM_QUEUE 0x02 +#define DRM_APU_GEM_DEQUEUE 0x03 +#define DRM_APU_NUM_IOCTLS 0x04 =20 #define DRM_IOCTL_APU_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_STATE, st= ruct drm_apu_state) #define DRM_IOCTL_APU_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_GEM_NEW= , struct drm_apu_gem_new) +#define DRM_IOCTL_APU_GEM_QUEUE DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_GEM_Q= UEUE, struct drm_apu_gem_queue) +#define DRM_IOCTL_APU_GEM_DEQUEUE DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_GEM_= DEQUEUE, struct drm_apu_gem_dequeue) =20 #if defined(__cplusplus) } --=20 2.39.2 From nobody Fri Sep 20 19:35:31 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C78A2C7EE23 for ; Wed, 17 May 2023 14:53:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232224AbjEQOxC (ORCPT ); Wed, 17 May 2023 10:53:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232209AbjEQOw6 (ORCPT ); Wed, 17 May 2023 10:52:58 -0400 Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C210F421E for ; Wed, 17 May 2023 07:52:49 -0700 (PDT) Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-3f427118644so8922955e9.0 for ; Wed, 17 May 2023 07:52:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1684335168; x=1686927168; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=UI38mzNCyvFGBkMAaNja4Azr5yleuYJIUin5avWU87w=; b=e74ivfotYAEvNLXSoqnCbQRc9OZxuaMFcKWG98sXJkM1UYMEbrDC+fZ+yf/fBn7rWm 7ZYq7pQyTY46To9Zy5Gvb3oSYZgv43cFQK23EdYNBEGiu0IwRUA/KSJ5ZxzOuJhpJq6L dTfLgSxLneb3v3GTWEqwfHYNIayKYpbczq4o9fhjIOCxCPWTd1A60a8PV5jCEn9IwF7w +nIpOmYu0OqA2D2yHnf96kTARb3U30oW1njUkybx3o7uPyGk5bB6XbSTklwWpKCZsw14 1hoU/E7mUYlbHWHjFFg94PJWraslcL1xCGN0eriq/kUM0mbzrRfeGpr3EwnQgd98LUXG xW5A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684335168; x=1686927168; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UI38mzNCyvFGBkMAaNja4Azr5yleuYJIUin5avWU87w=; b=b5+MH6q77YxrXt8BAqf2fP4pJoRFwVttbf5kZfQjUqiRqVu4LsKLnrekz+RLmm3TJk qJ9j6EnGKnW3MzulkcEq6xDyU1pE4hf1FayCZQVhqyXubA6vPpfero9vDcKR//wEPNGJ lPSPKQ99b8IO8oR5Z0Cf2wGYlpQ6c99jDk1MpBwCLpuxQ3xBm59fl8dGOT0y7EheJFmS /eVxUoMo5ph6Ws5AzzDl0HZozKdlhtZo2RRPhdNicPV8paoymVlYJJCW0r7cIV/6lMat v56M1M+S/hrfea7HucLyQuj1O8zxKpxcghPFbH4LMuOPrZe0mvypwgRQWdImsvfTHNJs sBlw== X-Gm-Message-State: AC+VfDwv6AnF0EALVxXRXheXIFoA7o9l4x5z9kaqOCOMMR6OcPZMQrfj 2VyeWQ2nPwzq/WqNN1bJlhHKsA== X-Google-Smtp-Source: ACHHUZ56bam5aYUqhbaIruRepK3WLO/dsctJUOsMK7UcXWOFFicMDzFlyXEYrjPGZ6kWWPArtbYqIQ== X-Received: by 2002:adf:f4d0:0:b0:307:873d:2ea with SMTP id h16-20020adff4d0000000b00307873d02eamr929458wrp.47.1684335168300; Wed, 17 May 2023 07:52:48 -0700 (PDT) Received: from blaptop.baylibre (laubervilliers-658-1-213-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) by smtp.gmail.com with ESMTPSA id v11-20020a5d678b000000b002f7780eee10sm2979098wru.59.2023.05.17.07.52.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 07:52:48 -0700 (PDT) From: Alexandre Bailon To: airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, sumit.semwal@linaro.org, christian.koenig@amd.com, jstephan@baylibre.com, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, khilman@baylibre.com, nbelin@baylibre.com, bero@baylibre.com, Alexandre Bailon Subject: [PATCH 4/7] drm/apu: Add support of IOMMU Date: Wed, 17 May 2023 16:52:34 +0200 Message-Id: <20230517145237.295461-5-abailon@baylibre.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230517145237.295461-1-abailon@baylibre.com> References: <20230517145237.295461-1-abailon@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Some APU devices are behind an IOMMU. For some of these devices, we can't use DMA API because they use static addresses so we have to manually use IOMMU API to correctly map the buffers. This adds support of IOMMU. Signed-off-by: Alexandre Bailon Reviewed-by: Julien Stephan --- drivers/gpu/drm/apu/apu_drv.c | 4 + drivers/gpu/drm/apu/apu_gem.c | 174 +++++++++++++++++++++++++++++ drivers/gpu/drm/apu/apu_internal.h | 16 +++ drivers/gpu/drm/apu/apu_sched.c | 28 +++++ include/uapi/drm/apu_drm.h | 12 +- 5 files changed, 233 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apu/apu_drv.c b/drivers/gpu/drm/apu/apu_drv.c index b6bd340b2bc8..a0dce785a02a 100644 --- a/drivers/gpu/drm/apu/apu_drv.c +++ b/drivers/gpu/drm/apu/apu_drv.c @@ -23,6 +23,10 @@ static const struct drm_ioctl_desc ioctls[] =3D { DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(APU_GEM_DEQUEUE, ioctl_gem_dequeue, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(APU_GEM_IOMMU_MAP, ioctl_gem_iommu_map, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(APU_GEM_IOMMU_UNMAP, ioctl_gem_iommu_unmap, + DRM_RENDER_ALLOW), }; =20 DEFINE_DRM_GEM_DMA_FOPS(apu_drm_ops); diff --git a/drivers/gpu/drm/apu/apu_gem.c b/drivers/gpu/drm/apu/apu_gem.c index 0e7b3b27942c..0a91363754c5 100644 --- a/drivers/gpu/drm/apu/apu_gem.c +++ b/drivers/gpu/drm/apu/apu_gem.c @@ -2,6 +2,9 @@ // // Copyright 2020 BayLibre SAS =20 +#include +#include + #include =20 #include @@ -42,6 +45,7 @@ int ioctl_gem_new(struct drm_device *dev, void *data, */ apu_obj->size =3D args->size; apu_obj->offset =3D 0; + apu_obj->iommu_refcount =3D 0; mutex_init(&apu_obj->mutex); =20 ret =3D drm_gem_handle_create(file_priv, gem_obj, &args->handle); @@ -54,3 +58,173 @@ int ioctl_gem_new(struct drm_device *dev, void *data, =20 return 0; } + +void apu_bo_iommu_unmap(struct apu_drm *apu_drm, struct apu_gem_object *ob= j) +{ + int iova_pfn; + int i; + + if (!obj->iommu_sgt) + return; + + mutex_lock(&obj->mutex); + obj->iommu_refcount--; + if (obj->iommu_refcount) { + mutex_unlock(&obj->mutex); + return; + } + + iova_pfn =3D PHYS_PFN(obj->iova); + for (i =3D 0; i < obj->iommu_sgt->nents; i++) { + iommu_unmap(apu_drm->domain, PFN_PHYS(iova_pfn), + PAGE_ALIGN(obj->iommu_sgt->sgl[i].length)); + iova_pfn +=3D PHYS_PFN(PAGE_ALIGN(obj->iommu_sgt->sgl[i].length)); + } + + sg_free_table(obj->iommu_sgt); + kfree(obj->iommu_sgt); + + free_iova(&apu_drm->iovad, PHYS_PFN(obj->iova)); + mutex_unlock(&obj->mutex); +} + +static struct sg_table *apu_get_sg_table(struct drm_gem_object *obj) +{ + if (obj->funcs) + return obj->funcs->get_sg_table(obj); + return NULL; +} + +int apu_bo_iommu_map(struct apu_drm *apu_drm, struct drm_gem_object *obj) +{ + struct apu_gem_object *apu_obj =3D to_apu_bo(obj); + struct scatterlist *sgl; + phys_addr_t phys; + int total_buf_space; + int iova_pfn; + int iova; + int ret; + int i; + + mutex_lock(&apu_obj->mutex); + apu_obj->iommu_refcount++; + if (apu_obj->iommu_refcount !=3D 1) { + mutex_unlock(&apu_obj->mutex); + return 0; + } + + apu_obj->iommu_sgt =3D apu_get_sg_table(obj); + if (IS_ERR(apu_obj->iommu_sgt)) { + mutex_unlock(&apu_obj->mutex); + return PTR_ERR(apu_obj->iommu_sgt); + } + + total_buf_space =3D obj->size; + iova_pfn =3D alloc_iova_fast(&apu_drm->iovad, + total_buf_space >> PAGE_SHIFT, + apu_drm->iova_limit_pfn, true); + apu_obj->iova =3D PFN_PHYS(iova_pfn); + + if (!iova_pfn) { + dev_err(apu_drm->dev, "Failed to allocate iova address\n"); + mutex_unlock(&apu_obj->mutex); + return -ENOMEM; + } + + iova =3D apu_obj->iova; + sgl =3D apu_obj->iommu_sgt->sgl; + for (i =3D 0; i < apu_obj->iommu_sgt->nents; i++) { + phys =3D page_to_phys(sg_page(&sgl[i])); + ret =3D + iommu_map(apu_drm->domain, PFN_PHYS(iova_pfn), phys, + PAGE_ALIGN(sgl[i].length), IOMMU_READ | IOMMU_WRITE, + GFP_KERNEL); + if (ret) { + dev_err(apu_drm->dev, "Failed to iommu map\n"); + free_iova(&apu_drm->iovad, iova_pfn); + mutex_unlock(&apu_obj->mutex); + return ret; + } + iova +=3D sgl[i].offset + sgl[i].length; + iova_pfn +=3D PHYS_PFN(PAGE_ALIGN(sgl[i].length)); + } + mutex_unlock(&apu_obj->mutex); + + return 0; +} + +int ioctl_gem_iommu_map(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct apu_drm *apu_drm =3D dev->dev_private; + struct drm_apu_gem_iommu_map *args =3D data; + struct drm_gem_object **bos; + void __user *bo_handles; + u64 *das; + int ret; + int i; + + if (!apu_drm->domain) + return -ENODEV; + + das =3D kvmalloc_array(args->bo_handle_count, sizeof(*das), GFP_KERNEL); + if (!das) + return -ENOMEM; + + bo_handles =3D (void __user *)(uintptr_t) args->bo_handles; + ret =3D drm_gem_objects_lookup(file_priv, bo_handles, + args->bo_handle_count, &bos); + if (ret) { + kvfree(das); + return ret; + } + + for (i =3D 0; i < args->bo_handle_count; i++) { + ret =3D apu_bo_iommu_map(apu_drm, bos[i]); + if (ret) { + /* TODO: handle error */ + break; + } + das[i] =3D to_apu_bo(bos[i])->iova + to_apu_bo(bos[i])->offset; + } + + if (copy_to_user((void *)args->bo_device_addresses, das, + args->bo_handle_count * sizeof(u64))) { + ret =3D -EFAULT; + DRM_DEBUG("Failed to copy device addresses\n"); + goto out; + } + +out: + kvfree(das); + kvfree(bos); + + return 0; +} + +int ioctl_gem_iommu_unmap(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct apu_drm *apu_drm =3D dev->dev_private; + struct drm_apu_gem_iommu_map *args =3D data; + struct drm_gem_object **bos; + void __user *bo_handles; + int ret; + int i; + + if (!apu_drm->domain) + return -ENODEV; + + bo_handles =3D (void __user *)(uintptr_t) args->bo_handles; + ret =3D drm_gem_objects_lookup(file_priv, bo_handles, + args->bo_handle_count, &bos); + if (ret) + return ret; + + for (i =3D 0; i < args->bo_handle_count; i++) + apu_bo_iommu_unmap(apu_drm, to_apu_bo(bos[i])); + + kvfree(bos); + + return 0; +} diff --git a/drivers/gpu/drm/apu/apu_internal.h b/drivers/gpu/drm/apu/apu_i= nternal.h index 021a3efdedf2..ea4183f3fb15 100644 --- a/drivers/gpu/drm/apu/apu_internal.h +++ b/drivers/gpu/drm/apu/apu_internal.h @@ -2,6 +2,9 @@ #ifndef __APU_INTERNAL_H__ #define __APU_INTERNAL_H__ =20 +#include +#include + #include #include #include @@ -9,7 +12,10 @@ struct apu_gem_object { struct drm_gem_dma_object base; struct mutex mutex; + struct sg_table *iommu_sgt; + int iommu_refcount; size_t size; + u32 iova; u32 offset; }; =20 @@ -35,6 +41,10 @@ struct apu_drm { struct drm_device base; struct device *dev; =20 + struct iommu_domain *domain; + struct iova_domain iovad; + int iova_limit_pfn; + struct list_head cores; struct list_head node; =20 @@ -165,12 +175,18 @@ struct apu_gem_object *to_apu_bo(struct drm_gem_objec= t *obj); struct drm_gem_object *apu_gem_create_object(struct drm_device *dev, size_t size); =20 +int apu_bo_iommu_map(struct apu_drm *apu_drm, struct drm_gem_object *obj); +void apu_bo_iommu_unmap(struct apu_drm *apu_drm, struct apu_gem_object *ob= j); int ioctl_gem_new(struct drm_device *dev, void *data, struct drm_file *file_priv); int ioctl_gem_user_new(struct drm_device *dev, void *data, struct drm_file *file_priv); struct dma_buf *apu_gem_prime_export(struct drm_gem_object *gem, int flags); +int ioctl_gem_iommu_map(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int ioctl_gem_iommu_unmap(struct drm_device *dev, void *data, + struct drm_file *file_priv); int ioctl_gem_queue(struct drm_device *dev, void *data, struct drm_file *file_priv); int ioctl_gem_dequeue(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/apu/apu_sched.c b/drivers/gpu/drm/apu/apu_sche= d.c index 13b6fbd00bd8..716d4b7f2d55 100644 --- a/drivers/gpu/drm/apu/apu_sched.c +++ b/drivers/gpu/drm/apu/apu_sched.c @@ -117,6 +117,8 @@ static void apu_job_cleanup(struct kref *ref) struct apu_gem_object *apu_obj; =20 apu_obj =3D to_apu_bo(job->bos[i]); + if (job->apu->domain) + apu_bo_iommu_unmap(job->apu, apu_obj); drm_gem_object_put(job->bos[i]); } =20 @@ -397,6 +399,7 @@ static int apu_lookup_bos(struct drm_device *dev, struc= t drm_file *file_priv, struct drm_apu_gem_queue *args, struct apu_job *job) { void __user *bo_handles; + unsigned int i; int ret; =20 job->bo_count =3D args->bo_handle_count; @@ -413,6 +416,31 @@ static int apu_lookup_bos(struct drm_device *dev, stru= ct drm_file *file_priv, bo_handles =3D (void __user *)(uintptr_t) args->bo_handles; ret =3D drm_gem_objects_lookup(file_priv, bo_handles, job->bo_count, &job->bos); + if (ret) + return ret; + + if (!job->apu->domain) + return 0; + + for (i =3D 0; i < job->bo_count; i++) { + ret =3D apu_bo_iommu_map(job->apu, job->bos[i]); + if (ret) + goto err_iommu_map; + } + + return ret; + +err_iommu_map: + kvfree(job->implicit_fences); + for (i =3D 0; i < job->bo_count; i++) { + struct apu_gem_object *apu_obj; + + apu_obj =3D to_apu_bo(job->bos[i]); + if (job->apu->domain) + apu_bo_iommu_unmap(job->apu, apu_obj); + drm_gem_object_put(job->bos[i]); + } + kvfree(job->bos); =20 return ret; } diff --git a/include/uapi/drm/apu_drm.h b/include/uapi/drm/apu_drm.h index c47000097040..0ecc739d8aed 100644 --- a/include/uapi/drm/apu_drm.h +++ b/include/uapi/drm/apu_drm.h @@ -41,6 +41,12 @@ struct drm_apu_gem_dequeue { __u64 data; }; =20 +struct drm_apu_gem_iommu_map { + __u64 bo_handles; + __u32 bo_handle_count; + __u64 bo_device_addresses; +}; + struct apu_job_event { struct drm_event base; __u32 out_sync; @@ -57,12 +63,16 @@ struct drm_apu_state { #define DRM_APU_GEM_NEW 0x01 #define DRM_APU_GEM_QUEUE 0x02 #define DRM_APU_GEM_DEQUEUE 0x03 -#define DRM_APU_NUM_IOCTLS 0x04 +#define DRM_APU_GEM_IOMMU_MAP 0x04 +#define DRM_APU_GEM_IOMMU_UNMAP 0x05 +#define DRM_APU_NUM_IOCTLS 0x06 =20 #define DRM_IOCTL_APU_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_STATE, st= ruct drm_apu_state) #define DRM_IOCTL_APU_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_GEM_NEW= , struct drm_apu_gem_new) #define DRM_IOCTL_APU_GEM_QUEUE DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_GEM_Q= UEUE, struct drm_apu_gem_queue) #define DRM_IOCTL_APU_GEM_DEQUEUE DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_GEM_= DEQUEUE, struct drm_apu_gem_dequeue) +#define DRM_IOCTL_APU_GEM_IOMMU_MAP DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_GE= M_IOMMU_MAP, struct drm_apu_gem_iommu_map) +#define DRM_IOCTL_APU_GEM_IOMMU_UNMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_= GEM_IOMMU_UNMAP, struct drm_apu_gem_iommu_map) =20 #if defined(__cplusplus) } --=20 2.39.2 From nobody Fri Sep 20 19:35:31 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E6D2EC77B7F for ; Wed, 17 May 2023 14:53:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230064AbjEQOxH (ORCPT ); Wed, 17 May 2023 10:53:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44734 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232213AbjEQOw6 (ORCPT ); Wed, 17 May 2023 10:52:58 -0400 Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D261583FE for ; Wed, 17 May 2023 07:52:50 -0700 (PDT) Received: by mail-wr1-x431.google.com with SMTP id ffacd0b85a97d-307c040797bso595412f8f.3 for ; Wed, 17 May 2023 07:52:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1684335169; x=1686927169; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ChL28icQVyizqOaIAH3gAMzq5UZ5InLkC1WcC+s6530=; b=iG7od/evTKtot/nJm1gK/1OL6Lc2v1Bmw9HJrvZNepXY3d+ijpP+DWiwPAyVpH4pE1 whGLUhjKSF4oMqvwtGaC3U7qu0JGLJf2iHcaZHG/KUWeDATqb+7kMGgK4oAbo+BiDQwI jpxA3KkT4mge9b6qQfuW6PavzHMyngFUeL5rUs8wtlXokzk0Gl/ytdd5BZqb0/1Z5e/Y cIV4AMhkBECqg1zNTCLE/3Y42tLbWIq2Tz99acBQU/rwUfG6htIKFOBvud87i13WKEpC cNz6RrsgVyoegDNgLU4Dj6l4jtXBZeukG92pSorCCUG0L5/O72DQRlJqUtdW4XruFu5P MPxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684335169; x=1686927169; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ChL28icQVyizqOaIAH3gAMzq5UZ5InLkC1WcC+s6530=; b=B37YqhOuFW5kO5EzM75I/kE+lzz0d4js90+HKduPw8HKEWXyd1DWt8IaBaAq4yFup5 4IfB5L2MtmS82kUaMjwuD0LdUhoIivQh63YRwLwKtWEyFyyKu9ZabUNedaTQpV+pzIYK We1YRn4SAW6IOcng9a4/O+sygICtLc3pXsbIQfOnB5YoM6Pwc6K+oC/q5IhMpfMlmPNq 1UbfFSARlcrb2oOVF38CfVtoGgPjB0oMLkGjhx/pJxK1UhYaifxyspB21dqvtAovSsxx SR2+Gb2lgkmr4RQY7/53hGSMUv3l8CJc+HmjRgQJKuXBmjDFoBKrrBnbHWIPwnm9lojz 3ZPA== X-Gm-Message-State: AC+VfDwUlQP8pTNNDglfu1c/Thn3iSk5tQG4fuGY7nraZcisu1UbuBjo lYmTItO7/Z91sUJ5rePRSSoveQ== X-Google-Smtp-Source: ACHHUZ5uCAqHjUKdV/6t3weODX6sjiburDexUUIvFFfFHhqo6Yq6iD6TS/qXA3nyRGAEZJG5rutnCQ== X-Received: by 2002:a5d:4cc9:0:b0:2fb:7099:6070 with SMTP id c9-20020a5d4cc9000000b002fb70996070mr839383wrt.47.1684335169252; Wed, 17 May 2023 07:52:49 -0700 (PDT) Received: from blaptop.baylibre (laubervilliers-658-1-213-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) by smtp.gmail.com with ESMTPSA id v11-20020a5d678b000000b002f7780eee10sm2979098wru.59.2023.05.17.07.52.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 07:52:48 -0700 (PDT) From: Alexandre Bailon To: airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, sumit.semwal@linaro.org, christian.koenig@amd.com, jstephan@baylibre.com, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, khilman@baylibre.com, nbelin@baylibre.com, bero@baylibre.com Subject: [PATCH 5/7] drm/apu: allow platform driver to implement their own mmap function Date: Wed, 17 May 2023 16:52:35 +0200 Message-Id: <20230517145237.295461-6-abailon@baylibre.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230517145237.295461-1-abailon@baylibre.com> References: <20230517145237.295461-1-abailon@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Julien Stephan By default we will call drm_gem_mmap() unless the apu driver has declared it's own mmap handler. Signed-off-by: Julien Stephan Reviewed-by: Julien Stephan --- drivers/gpu/drm/apu/apu_drv.c | 38 +++++++++++++++++++++++++++++- drivers/gpu/drm/apu/apu_internal.h | 2 ++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apu/apu_drv.c b/drivers/gpu/drm/apu/apu_drv.c index a0dce785a02a..703d4515f075 100644 --- a/drivers/gpu/drm/apu/apu_drv.c +++ b/drivers/gpu/drm/apu/apu_drv.c @@ -29,7 +29,20 @@ static const struct drm_ioctl_desc ioctls[] =3D { DRM_RENDER_ALLOW), }; =20 -DEFINE_DRM_GEM_DMA_FOPS(apu_drm_ops); +static int apu_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); + +static const struct file_operations apu_drm_ops =3D { + .owner =3D THIS_MODULE, + .open =3D drm_open, + .release =3D drm_release, + .unlocked_ioctl =3D drm_ioctl, + .compat_ioctl =3D drm_compat_ioctl, + .poll =3D drm_poll, + .read =3D drm_read, + .llseek =3D noop_llseek, + .mmap =3D apu_drm_gem_mmap, + DRM_GEM_DMA_UNMAPPED_AREA_FOPS +}; =20 static struct drm_driver apu_drm_driver =3D { .driver_features =3D DRIVER_GEM | DRIVER_SYNCOBJ, @@ -45,6 +58,29 @@ static struct drm_driver apu_drm_driver =3D { DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(drm_gem_dma_dumb_create), }; =20 +/** + * apu_drm_gem_mmap() + * + * @filp: DRM file pointer + * @vma: VMA for the area to be mapped + * + * by default will call drm_gem_mmap() unless the apu driver has declared = it's + * own mmap handler + * + */ +static int apu_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_file *priv =3D filp->private_data; + struct drm_device *dev =3D priv->minor->dev; + struct apu_drm *apu =3D dev->dev_private; + + if (apu->mmap) + return apu->mmap(filp, vma); + else + return drm_gem_mmap(filp, vma); +} + + /** * apu_dev_alloc() - Allocate a new APU device * diff --git a/drivers/gpu/drm/apu/apu_internal.h b/drivers/gpu/drm/apu/apu_i= nternal.h index ea4183f3fb15..46e0b2be7821 100644 --- a/drivers/gpu/drm/apu/apu_internal.h +++ b/drivers/gpu/drm/apu/apu_internal.h @@ -45,6 +45,8 @@ struct apu_drm { struct iova_domain iovad; int iova_limit_pfn; =20 + int (*mmap)(struct file *filp, struct vm_area_struct *vma); + struct list_head cores; struct list_head node; =20 --=20 2.39.2 From nobody Fri Sep 20 19:35:31 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EC77BC77B7D for ; Wed, 17 May 2023 14:53:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231350AbjEQOx1 (ORCPT ); Wed, 17 May 2023 10:53:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45416 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232215AbjEQOxL (ORCPT ); Wed, 17 May 2023 10:53:11 -0400 Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 33B598A7C for ; Wed, 17 May 2023 07:52:52 -0700 (PDT) Received: by mail-wr1-x42a.google.com with SMTP id ffacd0b85a97d-3078d1c8828so827183f8f.3 for ; Wed, 17 May 2023 07:52:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1684335170; x=1686927170; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=gDAViNn0OrgwOgKdIFqM87DFD/WIAZjGkg0w/gGFC28=; b=b495HJazHg0Ng27LlsAm3lPCnV9VhpPRLWdZE53fQIFVlD4GU+RbhZ1cJxnPFSwNdA HcaYLSCPi8KOFmOurLVZGHGjMdxvn88lPghdx5er/Cbi80/umddsZ7zO7m2tfEKWAhHc Rqe1i2VZkgTZsDe+1kw0bFvr6vSS0qmPSkat6oGaCBi2YGGwpbLADvUKY5s+nOHaRvu1 +EOiiQJVgnUepfVjzu0RsyNAp0X31Wa1aYGegDiRLMw1IcY0tpQwpSvMMS9BhqIuQHi/ NhnXfgb2H6jxdQcJSlExIsKcli4wUAZtwv/AwuTZ9eaOWwnCkE7hpmg7NpPu/uYhFXMz nqew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684335170; x=1686927170; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=gDAViNn0OrgwOgKdIFqM87DFD/WIAZjGkg0w/gGFC28=; b=QqjKpa5KgeTZ2X5u6nmBshSl4ApSbrlzzY6TQaW+sa53LZUzgpOURAAjNbxONjSbON G09dzIdQgq3RerMNM1fiziLzti62JcVCv5EI6THMHYaowZwm54ZLFI7rVZJAzkMsSD42 Cm6drD0g3I0DOYT4Y+HOocmvBcOZCiM1j0vgDVKaXlUaVSqaf1RT/1Nt+aI8cKFfS1di JJTG/1mpPCrJ5wtO/hEpuF+2rwj5G3TKNzu9HHt90xdhXtLFBxQ+zP4sP9npqf9YQYkx 1Fni3jHwexASXtDVXe5hKbq166TRHtaMbNFYVIv9DDB6iNHu7WqH2aWK5+X7I6mAFO0+ K6zw== X-Gm-Message-State: AC+VfDyOTGNjvZ/m0kDgDlU/5KzeaFMd53AB3JxaVn3JmVEpBQQC3v8H fM94NMzeQ2/rMyUGjJCWBlxQmw== X-Google-Smtp-Source: ACHHUZ6w4HWznKUY4Y6qU6rnRMXtzFEUnhSSv/0/k9+B8KB7LLKW0IPbU1ofdiJQhKloHX5gMjZa9w== X-Received: by 2002:a5d:5445:0:b0:306:2bb6:c7c3 with SMTP id w5-20020a5d5445000000b003062bb6c7c3mr921325wrv.6.1684335170471; Wed, 17 May 2023 07:52:50 -0700 (PDT) Received: from blaptop.baylibre (laubervilliers-658-1-213-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) by smtp.gmail.com with ESMTPSA id v11-20020a5d678b000000b002f7780eee10sm2979098wru.59.2023.05.17.07.52.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 07:52:49 -0700 (PDT) From: Alexandre Bailon To: airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, sumit.semwal@linaro.org, christian.koenig@amd.com, jstephan@baylibre.com, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, khilman@baylibre.com, nbelin@baylibre.com, bero@baylibre.com Subject: [PATCH 6/7] drm/apu: Add support for a simulated APU Date: Wed, 17 May 2023 16:52:36 +0200 Message-Id: <20230517145237.295461-7-abailon@baylibre.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230517145237.295461-1-abailon@baylibre.com> References: <20230517145237.295461-1-abailon@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Julien Stephan This implements a driver to use with a simulation APU. This is useful for testing purpose and can be used as a basis to implement real platform driver. Communication between the simulated APU and the driver is done using netlink socket. Signed-off-by: Julien Stephan --- drivers/gpu/drm/apu/Kconfig | 9 + drivers/gpu/drm/apu/Makefile | 3 + drivers/gpu/drm/apu/simu_apu.c | 313 +++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+) create mode 100644 drivers/gpu/drm/apu/simu_apu.c diff --git a/drivers/gpu/drm/apu/Kconfig b/drivers/gpu/drm/apu/Kconfig index a769df42091c..e0ffc166497c 100644 --- a/drivers/gpu/drm/apu/Kconfig +++ b/drivers/gpu/drm/apu/Kconfig @@ -11,3 +11,12 @@ config DRM_APU communicate with an AI Processor Unit (APU). The driver intends to provide a common infrastructure that may be used to support many different APU. + +config DRM_SIMU_APU + tristate "SIMULATION APU DRM driver" + depends on DRM_APU + default n + help + This provides a driver using netlink socket to communicate + with a simu APU. + This is useful for simulation and testing of libAPU stack. diff --git a/drivers/gpu/drm/apu/Makefile b/drivers/gpu/drm/apu/Makefile index fc8d6380fc38..0b007854a07f 100644 --- a/drivers/gpu/drm/apu/Makefile +++ b/drivers/gpu/drm/apu/Makefile @@ -4,4 +4,7 @@ drm_apu-y +=3D apu_drv.o drm_apu-y +=3D apu_gem.o drm_apu-y +=3D apu_sched.o =20 +drm_simu_apu-y +=3D simu_apu.o + obj-$(CONFIG_DRM_APU) +=3D drm_apu.o +obj-$(CONFIG_DRM_SIMU_APU) +=3D drm_simu_apu.o diff --git a/drivers/gpu/drm/apu/simu_apu.c b/drivers/gpu/drm/apu/simu_apu.c new file mode 100644 index 000000000000..5557f8b78a83 --- /dev/null +++ b/drivers/gpu/drm/apu/simu_apu.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2023 BayLibre SAS + +#include +#include +#include +#include + +#include + +#include + +#include "apu_internal.h" + + +#define MYPROTO 17 +#define MYGRP 17 + +#define DRIVER_NAME "SIMU APU DRIVER" + +/* + * Firmware request, must be aligned with the one defined in firmware. + * @id: Request id, used in the case of reply, to find the pending request + * @cmd: The command id to execute in the firmware + * @result: The result of the command executed on the firmware + * @size: The size of the data available in this request + * @count: The number of shared buffer + * @data: Contains the data attached with the request if size is greater t= han + * zero, and the addresses of shared buffers if count is greater than + * zero. Both the data and the shared buffer could be read and write + * by the APU. + */ +struct apu_dev_request { + u16 id; + u16 cmd; + u16 result; + u16 size_in; + u16 size_out; + u16 count; + u8 data[0]; +} __packed; + +struct platform_device *platform; +struct apu_core *apu_core; +static int pid =3D -1; +struct sock *nl_sock; + +static int apu_netlink_read(struct sk_buff *skb, struct apu_dev_request **= msg_ptr, int *pid) +{ + struct nlmsghdr *nlh; + + nlh =3D (struct nlmsghdr *)skb->data; + *pid =3D nlh->nlmsg_pid; /* pid of sending process */ + *msg_ptr =3D nlmsg_data(nlh); + + return nlh->nlmsg_len - NLMSG_HDRLEN; +} + +static int apu_netlink_write(void *msg_ptr, int msg_size, int pid) +{ + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + int res; + + skb_out =3D nlmsg_new(msg_size, 0); + if (!skb_out) + return -ENOMEM; + + nlh =3D nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); + NETLINK_CB(skb_out).dst_group =3D 0; /* not in multicast group */ + memcpy(nlmsg_data(nlh), msg_ptr, msg_size); + + res =3D nlmsg_unicast(nl_sock, skb_out, pid); + + if (res < 0) + return res; + else + return nlh->nlmsg_len - NLMSG_HDRLEN; +} + +static void netlink_recv_msg(struct sk_buff *skb) +{ + int msg_size; + struct apu_dev_request *hdr; + int nlmsg_pid; + + msg_size =3D apu_netlink_read(skb, &hdr, &nlmsg_pid); + + if (pid =3D=3D -1) { + // No device registered yet, the first message should be + // "READY" + if (!strncmp((char *)hdr, "READY", strlen("READY"))) { + + pid =3D nlmsg_pid; + if (apu_core_register(&platform->dev, apu_core, apu_core->apu)) + pr_err("cannot register SIMU APU\n"); + } + } else if (pid =3D=3D nlmsg_pid) { + if (!strncmp((char *)hdr, "STOP", strlen("STOP"))) { + pid =3D -1; + apu_core_remove(apu_core); + } else + apu_drm_callback(apu_core, hdr->id, hdr, msg_size); + } else { + pr_err("%s: Only one core is supported for now\n", DRIVER_NAME); + } +} + +static int netlink_setup(void) +{ + int ret =3D 0; + struct netlink_kernel_cfg cfg =3D { + .input =3D netlink_recv_msg, + }; + + nl_sock =3D netlink_kernel_create(&init_net, MYPROTO, &cfg); + if (!nl_sock) + ret =3D -ENOMEM; + + return ret; +} + +static int simu_apu_send(struct apu_job *job) +{ + return apu_netlink_write((void *)(job->request_data), job->request_len, p= id); +} + +static int simu_apu_handle_request(struct apu_job *job, void *data, int le= n) +{ + struct apu_dev_request *hdr =3D data; + + job->result =3D hdr->result; + if (job->size_out) + memcpy(job->data_out, hdr->data + job->size_in, + min(job->size_out, hdr->size_out)); + job->size_out =3D hdr->size_out; + return 0; +} + +static int simu_apu_alloc_request(struct apu_job *job) +{ + struct apu_dev_request *dev_req; + + int size; + u64 *dev_req_da; + u32 *dev_req_buffer_size; + int i; + + size =3D sizeof(*dev_req) + (sizeof(u64) + sizeof(u32)) * job->bo_count *= 2 + + job->size_in + job->size_out; + dev_req =3D kmalloc(size, GFP_KERNEL); + if (!dev_req) + return -ENOMEM; + + dev_req->cmd =3D job->cmd; + dev_req->size_in =3D job->size_in; + dev_req->size_out =3D job->size_out; + dev_req->count =3D job->bo_count; + dev_req_da =3D + (u64 *) (dev_req->data + dev_req->size_in + dev_req->size_out); + dev_req_buffer_size =3D (u32 *) (dev_req_da + dev_req->count); + memcpy(dev_req->data, job->data_in, job->size_in); + + for (i =3D 0; i < job->bo_count; i++) { + struct apu_gem_object *obj =3D to_apu_bo(job->bos[i]); + + dev_req_da[i] =3D drm_vma_node_offset_addr(&obj->base.base.vma_node); + dev_req_buffer_size[i] =3D obj->size; + } + + dev_req->id =3D job->id; + + job->request_data =3D dev_req; + job->request_len =3D size; + return 0; +} + +static int simu_apu_ready(struct apu_core *core) +{ + if (pid =3D=3D -1) + return 0; + + return 1; +} + +/** + * simu_apu_gem_mmap + * + * this is directly based on drm_gem_mmap() function but removing the perm= ission + * check before mapping a buffer. This is useful here to be able to easily + * share buffers between libapu host application and libapu device applica= tion + * (simulation use case) + * + */ +static int simu_apu_gem_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_file *priv =3D filp->private_data; + struct drm_device *dev =3D priv->minor->dev; + struct drm_gem_object *obj =3D NULL; + struct drm_vma_offset_node *node; + int ret; + + if (drm_dev_is_unplugged(dev)) + return -ENODEV; + + drm_vma_offset_lock_lookup(dev->vma_offset_manager); + node =3D drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager, + vma->vm_pgoff, + vma_pages(vma)); + if (likely(node)) { + obj =3D container_of(node, struct drm_gem_object, vma_node); + /* + * When the object is being freed, after it hits 0-refcnt it + * proceeds to tear down the object. In the process it will + * attempt to remove the VMA offset and so acquire this + * mgr->vm_lock. Therefore if we find an object with a 0-refcnt + * that matches our range, we know it is in the process of being + * destroyed and will be freed as soon as we release the lock - + * so we have to check for the 0-refcnted object and treat it as + * invalid. + */ + if (!kref_get_unless_zero(&obj->refcount)) { + obj =3D NULL; + pr_err("DTC: %s: %d\n", __func__, __LINE__); + } + } + drm_vma_offset_unlock_lookup(dev->vma_offset_manager); + + if (!obj) + return -EINVAL; + + ret =3D drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT, + vma); + + drm_gem_object_put(obj); + + return ret; +} + +static struct apu_core_ops simu_apu_ops =3D { + .alloc_prepare_request =3D simu_apu_alloc_request, + .send_request =3D simu_apu_send, + .handle_request =3D simu_apu_handle_request, + .is_ready =3D simu_apu_ready, +}; + +static int __init apu_platform_init(void) +{ + int ret; + struct apu_drm *apu; + + platform =3D platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); + if (IS_ERR(platform)) + return PTR_ERR(platform); + + if (!devres_open_group(&platform->dev, NULL, GFP_KERNEL)) { + ret =3D -ENOMEM; + goto out_unregister; + } + + apu =3D apu_dev_alloc(&platform->dev); + if (!apu) { + ret =3D -ENOMEM; + goto out_devres; + } + + apu_core =3D apu_core_alloc(apu, &simu_apu_ops, apu); + if (!apu_core) { + ret =3D -ENOMEM; + goto out_devres; + } + + ret =3D apu_dev_register(apu); + if (ret) + goto out_apu_core_free; + + apu->mmap =3D simu_apu_gem_mmap; + + ret =3D netlink_setup(); + if (ret) + goto out_apu_dev_unregister; + + return 0; + +out_apu_dev_unregister: + apu_dev_unregister(apu); +out_apu_core_free: + apu_core_free(apu_core); +out_devres: + devres_release_group(&platform->dev, NULL); +out_unregister: + platform_device_unregister(platform); + return ret; +} + +static void __exit apu_platform_exit(void) +{ + netlink_kernel_release(nl_sock); + apu_core_remove(apu_core); + apu_core_free(apu_core); + apu_dev_unregister((struct apu_drm *)apu_core->apu); + devres_release_group(&platform->dev, NULL); + platform_device_unregister(platform); +} + + +module_init(apu_platform_init); +module_exit(apu_platform_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Julien Stephan"); +MODULE_DESCRIPTION(DRIVER_NAME); --=20 2.39.2 From nobody Fri Sep 20 19:35:31 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 86E82C7EE23 for ; Wed, 17 May 2023 14:53:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232236AbjEQOxY (ORCPT ); Wed, 17 May 2023 10:53:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44640 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232197AbjEQOxL (ORCPT ); Wed, 17 May 2023 10:53:11 -0400 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1F39F8684 for ; Wed, 17 May 2023 07:52:53 -0700 (PDT) Received: by mail-wm1-x342.google.com with SMTP id 5b1f17b1804b1-3f4c6c4b51eso8852465e9.2 for ; Wed, 17 May 2023 07:52:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20221208.gappssmtp.com; s=20221208; t=1684335171; x=1686927171; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9mr1L/m4ima+2h/NhXtcjqbHddpi6u41EWoGArxh1iQ=; b=pdG2+3ODw0cGuNg/LORzvNsUqX1IiweDfrWioVGocQZDWZOWLRqkDaX4MTzyiQe1c7 pkyEeUQ7xqMrhFPqgtTXbdZp3T0rwW0l0BIMsILSnzXcX/Sd7NVDoMo/aiSxsYvHmvbE 9CFhqMy1vU2U8NqgvLhl8WgFol9WpTF6r6EFUqq/RKyHw1v7dAJHBpN4C35EGlhKFu2m bv8X2zua8yim+q2TU1Nwjf+yYUMToKg1IrzAFE9ZZPxUgS9V2JJXJY3xZezoYKEGwVXh 5JUMdyDg8DXWWvuNp3X07uEX8GvfXlSZm2H1ourLwVfh0bfHuRQHtAUbRtnalP8rK24w 5aJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684335171; x=1686927171; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9mr1L/m4ima+2h/NhXtcjqbHddpi6u41EWoGArxh1iQ=; b=FK91trCQ77mNNXTeBVMRVzCXMwHbab9B48/lOkACQC5H+ApKxIlth4JEPejEDXZXrK Tc6PVwmaWOENtnGHi+mt+G+bakUpWfnZUpfob+s/GygGhnYjS96bu70M43bUQU/4JHvT 8q04YrI527YNSqniOdz9ktGKOVTyVJzmkn0afWM+01VVkcRYky/5ij5wjBv3BkH/ja2h V7UTB2Ve0ca495FubUBbkkzJZj585s8FXxeZKvxL1zQWgkvjb7xm5jxfOEKHRBx3Rw25 NjN2w3tuU0+PFtv7UhaJMvIDXS1zMolXUKoSMSAwgCb8/gFvUbbRp/saNnw6dHMc7EJp XBRQ== X-Gm-Message-State: AC+VfDwm9KELZCYcC4ZdkLFFpyzwKqlGJVBC1NyWj+YkO5R9tXvx2b1e PJAovpPfugCcLv0bQGbfZrsR3w== X-Google-Smtp-Source: ACHHUZ7D+XIYOY7fwEt1VA+EKenIzVfyhPoXQPx4ACohe42JP1CZtzERdmroTv625PctD16NHx1kmg== X-Received: by 2002:adf:e450:0:b0:307:97dd:1de2 with SMTP id t16-20020adfe450000000b0030797dd1de2mr930581wrm.25.1684335171626; Wed, 17 May 2023 07:52:51 -0700 (PDT) Received: from blaptop.baylibre (laubervilliers-658-1-213-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) by smtp.gmail.com with ESMTPSA id v11-20020a5d678b000000b002f7780eee10sm2979098wru.59.2023.05.17.07.52.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 May 2023 07:52:51 -0700 (PDT) From: Alexandre Bailon To: airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, sumit.semwal@linaro.org, christian.koenig@amd.com, jstephan@baylibre.com, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, khilman@baylibre.com, nbelin@baylibre.com, bero@baylibre.com, Alexandre Bailon Subject: [PATCH 7/7] dt-bindings: Add bidings for mtk,apu-drm Date: Wed, 17 May 2023 16:52:37 +0200 Message-Id: <20230517145237.295461-8-abailon@baylibre.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230517145237.295461-1-abailon@baylibre.com> References: <20230517145237.295461-1-abailon@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds the device tree bindings for the APU DRM driver. Signed-off-by: Alexandre Bailon Reviewed-by: Julien Stephan --- .../devicetree/bindings/gpu/mtk,apu-drm.yaml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/mtk,apu-drm.yaml diff --git a/Documentation/devicetree/bindings/gpu/mtk,apu-drm.yaml b/Docum= entation/devicetree/bindings/gpu/mtk,apu-drm.yaml new file mode 100644 index 000000000000..6f432d3ea478 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/mtk,apu-drm.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/mediatek,apu-drm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AI Processor Unit DRM + +properties: + compatible: + const: mediatek,apu-drm + + remoteproc: + maxItems: 2 + description: + Handle to remoteproc devices controlling the APU + + iova: + maxItems: 1 + description: + Address and size of virtual memory that could used by the APU + +required: + - compatible + - remoteproc + - iova + +additionalProperties: false + +examples: + - | + apu@0 { + compatible =3D "mediatek,apu-drm"; + remoteproc =3D <&vpu0>, <&vpu1>; + iova =3D <0 0x60000000 0 0x10000000>; + }; + +... --=20 2.39.2