Commit 17a74021 authored by Ben Skeggs's avatar Ben Skeggs Committed by Dave Airlie

drm/nouveau/nvkm: support loading fws into sg_table

- preparation for GSP-RM, which has massive FW images
- based on a patch by Dave Airlie
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230918202149.4343-32-skeggsb@gmail.com
parent e672f5f3
...@@ -10,6 +10,7 @@ struct nvkm_firmware { ...@@ -10,6 +10,7 @@ struct nvkm_firmware {
enum nvkm_firmware_type { enum nvkm_firmware_type {
NVKM_FIRMWARE_IMG_RAM, NVKM_FIRMWARE_IMG_RAM,
NVKM_FIRMWARE_IMG_DMA, NVKM_FIRMWARE_IMG_DMA,
NVKM_FIRMWARE_IMG_SGT,
} type; } type;
} *func; } *func;
const char *name; const char *name;
...@@ -21,7 +22,10 @@ struct nvkm_firmware { ...@@ -21,7 +22,10 @@ struct nvkm_firmware {
struct nvkm_firmware_mem { struct nvkm_firmware_mem {
struct nvkm_memory memory; struct nvkm_memory memory;
struct scatterlist sgl; union {
struct scatterlist sgl; /* DMA */
struct sg_table sgt; /* SGT */
};
} mem; } mem;
}; };
......
...@@ -112,6 +112,22 @@ nvkm_firmware_put(const struct firmware *fw) ...@@ -112,6 +112,22 @@ nvkm_firmware_put(const struct firmware *fw)
#define nvkm_firmware_mem(p) container_of((p), struct nvkm_firmware, mem.memory) #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 static int
nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm, nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm,
struct nvkm_vma *vma, void *argv, u32 argc) struct nvkm_vma *vma, void *argv, u32 argc)
...@@ -120,10 +136,10 @@ nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *v ...@@ -120,10 +136,10 @@ nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *v
struct nvkm_vmm_map map = { struct nvkm_vmm_map map = {
.memory = &fw->mem.memory, .memory = &fw->mem.memory,
.offset = offset, .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 -ENOSYS;
return nvkm_vmm_map(vmm, vma, argv, argc, &map); return nvkm_vmm_map(vmm, vma, argv, argc, &map);
...@@ -132,12 +148,15 @@ nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *v ...@@ -132,12 +148,15 @@ nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *v
static u64 static u64
nvkm_firmware_mem_size(struct nvkm_memory *memory) 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 static u64
nvkm_firmware_mem_addr(struct nvkm_memory *memory) 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; return nvkm_firmware_mem(memory)->phys;
} }
...@@ -188,6 +207,12 @@ nvkm_firmware_dtor(struct nvkm_firmware *fw) ...@@ -188,6 +207,12 @@ nvkm_firmware_dtor(struct nvkm_firmware *fw)
nvkm_memory_unref(&memory); nvkm_memory_unref(&memory);
dma_free_coherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), fw->img, fw->phys); dma_free_coherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), fw->img, fw->phys);
break; 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: default:
WARN_ON(1); WARN_ON(1);
break; break;
...@@ -225,6 +250,49 @@ nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name, ...@@ -225,6 +250,49 @@ nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name,
sg_dma_len(&fw->mem.sgl) = len; sg_dma_len(&fw->mem.sgl) = len;
} }
break; 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: default:
WARN_ON(1); WARN_ON(1);
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment