@@ -112,6 +112,22 @@ nvkm_firmware_put(const struct firmware *fw)
112
112
113
113
#define nvkm_firmware_mem (p ) container_of((p), struct nvkm_firmware, mem.memory)
114
114
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
+
115
131
static int
116
132
nvkm_firmware_mem_map (struct nvkm_memory * memory , u64 offset , struct nvkm_vmm * vmm ,
117
133
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
136
struct nvkm_vmm_map map = {
121
137
.memory = & fw -> mem .memory ,
122
138
.offset = offset ,
123
- .sgl = & fw -> mem . sgl ,
139
+ .sgl = nvkm_firmware_mem_sgl ( memory ) ,
124
140
};
125
141
126
- if (WARN_ON ( fw -> func -> type != NVKM_FIRMWARE_IMG_DMA ) )
142
+ if (! map . sgl )
127
143
return - ENOSYS ;
128
144
129
145
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
148
static u64
133
149
nvkm_firmware_mem_size (struct nvkm_memory * memory )
134
150
{
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 ;
136
154
}
137
155
138
156
static u64
139
157
nvkm_firmware_mem_addr (struct nvkm_memory * memory )
140
158
{
159
+ BUG_ON (nvkm_firmware_mem (memory )-> func -> type != NVKM_FIRMWARE_IMG_DMA );
141
160
return nvkm_firmware_mem (memory )-> phys ;
142
161
}
143
162
@@ -188,6 +207,12 @@ nvkm_firmware_dtor(struct nvkm_firmware *fw)
188
207
nvkm_memory_unref (& memory );
189
208
dma_free_coherent (fw -> device -> dev , sg_dma_len (& fw -> mem .sgl ), fw -> img , fw -> phys );
190
209
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 ;
191
216
default :
192
217
WARN_ON (1 );
193
218
break ;
@@ -225,6 +250,49 @@ nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name,
225
250
sg_dma_len (& fw -> mem .sgl ) = len ;
226
251
}
227
252
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 ;
228
296
default :
229
297
WARN_ON (1 );
230
298
return - EINVAL ;
0 commit comments