Skip to content

Commit 17a7402

Browse files
Ben Skeggsairlied
authored andcommitted
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 <[email protected]> Signed-off-by: Dave Airlie <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent e672f5f commit 17a7402

File tree

2 files changed

+76
-4
lines changed

2 files changed

+76
-4
lines changed

drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ struct nvkm_firmware {
1010
enum nvkm_firmware_type {
1111
NVKM_FIRMWARE_IMG_RAM,
1212
NVKM_FIRMWARE_IMG_DMA,
13+
NVKM_FIRMWARE_IMG_SGT,
1314
} type;
1415
} *func;
1516
const char *name;
@@ -21,7 +22,10 @@ struct nvkm_firmware {
2122

2223
struct nvkm_firmware_mem {
2324
struct nvkm_memory memory;
24-
struct scatterlist sgl;
25+
union {
26+
struct scatterlist sgl; /* DMA */
27+
struct sg_table sgt; /* SGT */
28+
};
2529
} mem;
2630
};
2731

drivers/gpu/drm/nouveau/nvkm/core/firmware.c

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,22 @@ nvkm_firmware_put(const struct firmware *fw)
112112

113113
#define nvkm_firmware_mem(p) container_of((p), struct nvkm_firmware, mem.memory)
114114

115+
static struct scatterlist *
116+
nvkm_firmware_mem_sgl(struct nvkm_memory *memory)
117+
{
118+
struct nvkm_firmware *fw = nvkm_firmware_mem(memory);
119+
120+
switch (fw->func->type) {
121+
case NVKM_FIRMWARE_IMG_DMA: return &fw->mem.sgl;
122+
case NVKM_FIRMWARE_IMG_SGT: return fw->mem.sgt.sgl;
123+
default:
124+
WARN_ON(1);
125+
break;
126+
}
127+
128+
return NULL;
129+
}
130+
115131
static int
116132
nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm,
117133
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
120136
struct nvkm_vmm_map map = {
121137
.memory = &fw->mem.memory,
122138
.offset = offset,
123-
.sgl = &fw->mem.sgl,
139+
.sgl = nvkm_firmware_mem_sgl(memory),
124140
};
125141

126-
if (WARN_ON(fw->func->type != NVKM_FIRMWARE_IMG_DMA))
142+
if (!map.sgl)
127143
return -ENOSYS;
128144

129145
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
132148
static u64
133149
nvkm_firmware_mem_size(struct nvkm_memory *memory)
134150
{
135-
return sg_dma_len(&nvkm_firmware_mem(memory)->mem.sgl);
151+
struct scatterlist *sgl = nvkm_firmware_mem_sgl(memory);
152+
153+
return sgl ? sg_dma_len(sgl) : 0;
136154
}
137155

138156
static u64
139157
nvkm_firmware_mem_addr(struct nvkm_memory *memory)
140158
{
159+
BUG_ON(nvkm_firmware_mem(memory)->func->type != NVKM_FIRMWARE_IMG_DMA);
141160
return nvkm_firmware_mem(memory)->phys;
142161
}
143162

@@ -188,6 +207,12 @@ nvkm_firmware_dtor(struct nvkm_firmware *fw)
188207
nvkm_memory_unref(&memory);
189208
dma_free_coherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), fw->img, fw->phys);
190209
break;
210+
case NVKM_FIRMWARE_IMG_SGT:
211+
nvkm_memory_unref(&memory);
212+
dma_unmap_sgtable(fw->device->dev, &fw->mem.sgt, DMA_TO_DEVICE, 0);
213+
sg_free_table(&fw->mem.sgt);
214+
vfree(fw->img);
215+
break;
191216
default:
192217
WARN_ON(1);
193218
break;
@@ -225,6 +250,49 @@ nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name,
225250
sg_dma_len(&fw->mem.sgl) = len;
226251
}
227252
break;
253+
case NVKM_FIRMWARE_IMG_SGT:
254+
len = ALIGN(fw->len, PAGE_SIZE);
255+
256+
fw->img = vmalloc(len);
257+
if (fw->img) {
258+
int pages = len >> PAGE_SHIFT;
259+
int ret = 0;
260+
261+
memcpy(fw->img, src, fw->len);
262+
263+
ret = sg_alloc_table(&fw->mem.sgt, pages, GFP_KERNEL);
264+
if (ret == 0) {
265+
struct scatterlist *sgl;
266+
u8 *data = fw->img;
267+
int i;
268+
269+
for_each_sgtable_sg(&fw->mem.sgt, sgl, i) {
270+
struct page *page = vmalloc_to_page(data);
271+
272+
if (!page) {
273+
ret = -EFAULT;
274+
break;
275+
}
276+
277+
sg_set_page(sgl, page, PAGE_SIZE, 0);
278+
data += PAGE_SIZE;
279+
}
280+
281+
if (ret == 0) {
282+
ret = dma_map_sgtable(fw->device->dev, &fw->mem.sgt,
283+
DMA_TO_DEVICE, 0);
284+
}
285+
286+
if (ret)
287+
sg_free_table(&fw->mem.sgt);
288+
}
289+
290+
if (ret) {
291+
vfree(fw->img);
292+
fw->img = NULL;
293+
}
294+
}
295+
break;
228296
default:
229297
WARN_ON(1);
230298
return -EINVAL;

0 commit comments

Comments
 (0)