@@ -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+
115131static int
116132nvkm_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
132148static u64
133149nvkm_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
138156static u64
139157nvkm_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