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: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230918202149.4343-32-skeggsb@gmail.com
This commit is contained in:
parent
e672f5f30d
commit
17a74021a3
@ -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;
|
||||
};
|
||||
|
||||
|
@ -112,6 +112,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)
|
||||
@ -120,10 +136,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);
|
||||
@ -132,12 +148,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;
|
||||
}
|
||||
|
||||
@ -188,6 +207,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;
|
||||
@ -225,6 +250,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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user