[Nouveau] [PATCH 31/44] drm/nouveau/nvkm: support loading fws into sg_table
Philipp Stanner
pstanner at redhat.com
Tue Oct 24 09:20:32 UTC 2023
On Tue, 2023-09-19 at 06:21 +1000, Ben Skeggs wrote:
> From: Ben Skeggs <bskeggs at redhat.com>
>
> - preparation for GSP-RM, which has massive FW images
> - based on a patch by Dave Airlie
Probably more canonical to use one of the standard phrases such as
Suggested-by
>
> Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
> ---
> .../drm/nouveau/include/nvkm/core/firmware.h | 6 +-
> drivers/gpu/drm/nouveau/nvkm/core/firmware.c | 74
> ++++++++++++++++++-
> 2 files changed, 76 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h
> b/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h
> index d4e507e252b1..20839be72644 100644
> --- a/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h
> +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h
> @@ -10,6 +10,7 @@ struct nvkm_firmware {
> enum nvkm_firmware_type {
> NVKM_FIRMWARE_IMG_RAM,
> NVKM_FIRMWARE_IMG_DMA,
> + NVKM_FIRMWARE_IMG_SGT,
> } type;
> } *func;
> const char *name;
> @@ -21,7 +22,10 @@ struct nvkm_firmware {
>
> struct nvkm_firmware_mem {
> struct nvkm_memory memory;
> - struct scatterlist sgl;
> + union {
> + struct scatterlist sgl; /* DMA */
> + struct sg_table sgt; /* SGT */
> + };
> } mem;
> };
>
> diff --git a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
> b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
> index 91fb494d4009..4641e7eebe56 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
> @@ -113,6 +113,22 @@ nvkm_firmware_put(const struct firmware *fw)
>
> #define nvkm_firmware_mem(p) container_of((p), struct nvkm_firmware,
> mem.memory)
>
> +static struct scatterlist *
> +nvkm_firmware_mem_sgl(struct nvkm_memory *memory)
> +{
> + struct nvkm_firmware *fw = nvkm_firmware_mem(memory);
> +
> + switch (fw->func->type) {
> + case NVKM_FIRMWARE_IMG_DMA: return &fw->mem.sgl;
> + case NVKM_FIRMWARE_IMG_SGT: return fw->mem.sgt.sgl;
> + default:
> + WARN_ON(1);
> + break;
> + }
> +
> + return NULL;
> +}
> +
> static int
> nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct
> nvkm_vmm *vmm,
> struct nvkm_vma *vma, void *argv, u32 argc)
> @@ -121,10 +137,10 @@ nvkm_firmware_mem_map(struct nvkm_memory
> *memory, u64 offset, struct nvkm_vmm *v
> struct nvkm_vmm_map map = {
> .memory = &fw->mem.memory,
> .offset = offset,
> - .sgl = &fw->mem.sgl,
> + .sgl = nvkm_firmware_mem_sgl(memory),
> };
>
> - if (WARN_ON(fw->func->type != NVKM_FIRMWARE_IMG_DMA))
> + if (!map.sgl)
> return -ENOSYS;
>
> return nvkm_vmm_map(vmm, vma, argv, argc, &map);
> @@ -133,12 +149,15 @@ nvkm_firmware_mem_map(struct nvkm_memory
> *memory, u64 offset, struct nvkm_vmm *v
> static u64
> nvkm_firmware_mem_size(struct nvkm_memory *memory)
> {
> - return sg_dma_len(&nvkm_firmware_mem(memory)->mem.sgl);
> + struct scatterlist *sgl = nvkm_firmware_mem_sgl(memory);
> +
> + return sgl ? sg_dma_len(sgl) : 0;
> }
>
> static u64
> nvkm_firmware_mem_addr(struct nvkm_memory *memory)
> {
> + BUG_ON(nvkm_firmware_mem(memory)->func->type !=
> NVKM_FIRMWARE_IMG_DMA);
> return nvkm_firmware_mem(memory)->phys;
> }
>
> @@ -189,6 +208,12 @@ nvkm_firmware_dtor(struct nvkm_firmware *fw)
> nvkm_memory_unref(&memory);
> dma_free_coherent(fw->device->dev, sg_dma_len(&fw-
> >mem.sgl), fw->img, fw->phys);
> break;
> + case NVKM_FIRMWARE_IMG_SGT:
> + nvkm_memory_unref(&memory);
> + dma_unmap_sgtable(fw->device->dev, &fw->mem.sgt,
> DMA_TO_DEVICE, 0);
> + sg_free_table(&fw->mem.sgt);
> + vfree(fw->img);
> + break;
> default:
> WARN_ON(1);
> break;
> @@ -226,6 +251,49 @@ nvkm_firmware_ctor(const struct
> nvkm_firmware_func *func, const char *name,
> sg_dma_len(&fw->mem.sgl) = len;
> }
> break;
> + case NVKM_FIRMWARE_IMG_SGT:
> + len = ALIGN(fw->len, PAGE_SIZE);
> +
> + fw->img = vmalloc(len);
> + if (fw->img) {
> + int pages = len >> PAGE_SHIFT;
> + int ret = 0;
> +
> + memcpy(fw->img, src, fw->len);
> +
> + ret = sg_alloc_table(&fw->mem.sgt, pages,
> GFP_KERNEL);
> + if (ret == 0) {
> + struct scatterlist *sgl;
> + u8 *data = fw->img;
> + int i;
> +
> + for_each_sgtable_sg(&fw->mem.sgt,
> sgl, i) {
> + struct page *page =
> vmalloc_to_page(data);
> +
> + if (!page) {
> + ret = -EFAULT;
> + break;
> + }
> +
> + sg_set_page(sgl, page,
> PAGE_SIZE, 0);
> + data += PAGE_SIZE;
> + }
> +
> + if (ret == 0) {
> + ret = dma_map_sgtable(fw-
> >device->dev, &fw->mem.sgt,
> +
> DMA_TO_DEVICE, 0);
> + }
> +
> + if (ret)
> + sg_free_table(&fw->mem.sgt);
> + }
> +
> + if (ret) {
> + vfree(fw->img);
> + fw->img = NULL;
> + }
> + }
> + break;
> default:
> WARN_ON(1);
> return -EINVAL;
More information about the Nouveau
mailing list