Linux Audio

Check our new training course

Loading...
v4.6
 1/*
 2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
 3 *
 4 * Permission is hereby granted, free of charge, to any person obtaining a
 5 * copy of this software and associated documentation files (the "Software"),
 6 * to deal in the Software without restriction, including without limitation
 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 8 * and/or sell copies of the Software, and to permit persons to whom the
 9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22#include <core/device.h>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
24/**
25 * nvkm_firmware_get - load firmware from the official nvidia/chip/ directory
26 * @device	device that will use that firmware
27 * @fwname	name of firmware file to load
28 * @fw		firmware structure to load to
 
29 *
30 * Use this function to load firmware files in the form nvidia/chip/fwname.bin.
31 * Firmware files released by NVIDIA will always follow this format.
32 */
33int
34nvkm_firmware_get(struct nvkm_device *device, const char *fwname,
35		  const struct firmware **fw)
36{
 
37	char f[64];
38	char cname[16];
39	int i;
40
41	/* Convert device name to lowercase */
42	strncpy(cname, device->chip->name, sizeof(cname));
43	cname[sizeof(cname) - 1] = '\0';
44	i = strlen(cname);
45	while (i) {
46		--i;
47		cname[i] = tolower(cname[i]);
48	}
49
50	snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname);
51	return request_firmware(fw, f, device->dev);
 
 
 
 
 
 
 
 
 
 
 
52}
53
54/**
55 * nvkm_firmware_put - release firmware loaded with nvkm_firmware_get
56 */
57void
58nvkm_firmware_put(const struct firmware *fw)
59{
60	release_firmware(fw);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61}
v6.8
  1/*
  2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 20 * DEALINGS IN THE SOFTWARE.
 21 */
 22#include <core/device.h>
 23#include <core/firmware.h>
 24
 25#include <subdev/fb.h>
 26#include <subdev/mmu.h>
 27
 28int
 29nvkm_firmware_load_name(const struct nvkm_subdev *subdev, const char *base,
 30			const char *name, int ver, const struct firmware **pfw)
 31{
 32	char path[64];
 33	int ret;
 34
 35	snprintf(path, sizeof(path), "%s%s", base, name);
 36	ret = nvkm_firmware_get(subdev, path, ver, pfw);
 37	if (ret < 0)
 38		return ret;
 39
 40	return 0;
 41}
 42
 43int
 44nvkm_firmware_load_blob(const struct nvkm_subdev *subdev, const char *base,
 45			const char *name, int ver, struct nvkm_blob *blob)
 46{
 47	const struct firmware *fw;
 48	int ret;
 49
 50	ret = nvkm_firmware_load_name(subdev, base, name, ver, &fw);
 51	if (ret == 0) {
 52		blob->data = kmemdup(fw->data, fw->size, GFP_KERNEL);
 53		blob->size = fw->size;
 54		nvkm_firmware_put(fw);
 55		if (!blob->data)
 56			return -ENOMEM;
 57	}
 58
 59	return ret;
 60}
 61
 62/**
 63 * nvkm_firmware_get - load firmware from the official nvidia/chip/ directory
 64 * @subdev:	subdevice that will use that firmware
 65 * @fwname:	name of firmware file to load
 66 * @ver:	firmware version to load
 67 * @fw:		firmware structure to load to
 68 *
 69 * Use this function to load firmware files in the form nvidia/chip/fwname.bin.
 70 * Firmware files released by NVIDIA will always follow this format.
 71 */
 72int
 73nvkm_firmware_get(const struct nvkm_subdev *subdev, const char *fwname, int ver,
 74		  const struct firmware **fw)
 75{
 76	struct nvkm_device *device = subdev->device;
 77	char f[64];
 78	char cname[16];
 79	int i;
 80
 81	/* Convert device name to lowercase */
 82	strscpy(cname, device->chip->name, sizeof(cname));
 
 83	i = strlen(cname);
 84	while (i) {
 85		--i;
 86		cname[i] = tolower(cname[i]);
 87	}
 88
 89	if (ver != 0)
 90		snprintf(f, sizeof(f), "nvidia/%s/%s-%d.bin", cname, fwname, ver);
 91	else
 92		snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname);
 93
 94	if (!firmware_request_nowarn(fw, f, device->dev)) {
 95		nvkm_debug(subdev, "firmware \"%s\" loaded - %zu byte(s)\n",
 96			   f, (*fw)->size);
 97		return 0;
 98	}
 99
100	nvkm_debug(subdev, "firmware \"%s\" unavailable\n", f);
101	return -ENOENT;
102}
103
104/*
105 * nvkm_firmware_put - release firmware loaded with nvkm_firmware_get
106 */
107void
108nvkm_firmware_put(const struct firmware *fw)
109{
110	release_firmware(fw);
111}
112
113#define nvkm_firmware_mem(p) container_of((p), struct nvkm_firmware, mem.memory)
114
115static struct scatterlist *
116nvkm_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
131static int
132nvkm_firmware_mem_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm,
133		      struct nvkm_vma *vma, void *argv, u32 argc)
134{
135	struct nvkm_firmware *fw = nvkm_firmware_mem(memory);
136	struct nvkm_vmm_map map = {
137		.memory = &fw->mem.memory,
138		.offset = offset,
139		.sgl = nvkm_firmware_mem_sgl(memory),
140	};
141
142	if (!map.sgl)
143		return -ENOSYS;
144
145	return nvkm_vmm_map(vmm, vma, argv, argc, &map);
146}
147
148static u64
149nvkm_firmware_mem_size(struct nvkm_memory *memory)
150{
151	struct scatterlist *sgl = nvkm_firmware_mem_sgl(memory);
152
153	return sgl ? sg_dma_len(sgl) : 0;
154}
155
156static u64
157nvkm_firmware_mem_addr(struct nvkm_memory *memory)
158{
159	BUG_ON(nvkm_firmware_mem(memory)->func->type != NVKM_FIRMWARE_IMG_DMA);
160	return nvkm_firmware_mem(memory)->phys;
161}
162
163static u8
164nvkm_firmware_mem_page(struct nvkm_memory *memory)
165{
166	return PAGE_SHIFT;
167}
168
169static enum nvkm_memory_target
170nvkm_firmware_mem_target(struct nvkm_memory *memory)
171{
172	if (nvkm_firmware_mem(memory)->device->func->tegra)
173		return NVKM_MEM_TARGET_NCOH;
174
175	return NVKM_MEM_TARGET_HOST;
176}
177
178static void *
179nvkm_firmware_mem_dtor(struct nvkm_memory *memory)
180{
181	return NULL;
182}
183
184static const struct nvkm_memory_func
185nvkm_firmware_mem = {
186	.dtor = nvkm_firmware_mem_dtor,
187	.target = nvkm_firmware_mem_target,
188	.page = nvkm_firmware_mem_page,
189	.addr = nvkm_firmware_mem_addr,
190	.size = nvkm_firmware_mem_size,
191	.map = nvkm_firmware_mem_map,
192};
193
194void
195nvkm_firmware_dtor(struct nvkm_firmware *fw)
196{
197	struct nvkm_memory *memory = &fw->mem.memory;
198
199	if (!fw->img)
200		return;
201
202	switch (fw->func->type) {
203	case NVKM_FIRMWARE_IMG_RAM:
204		kfree(fw->img);
205		break;
206	case NVKM_FIRMWARE_IMG_DMA:
207		nvkm_memory_unref(&memory);
208		dma_free_coherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), fw->img, fw->phys);
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;
216	default:
217		WARN_ON(1);
218		break;
219	}
220
221	fw->img = NULL;
222}
223
224int
225nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name,
226		   struct nvkm_device *device, const void *src, int len, struct nvkm_firmware *fw)
227{
228	fw->func = func;
229	fw->name = name;
230	fw->device = device;
231	fw->len = len;
232
233	switch (fw->func->type) {
234	case NVKM_FIRMWARE_IMG_RAM:
235		fw->img = kmemdup(src, fw->len, GFP_KERNEL);
236		break;
237	case NVKM_FIRMWARE_IMG_DMA: {
238		dma_addr_t addr;
239
240		len = ALIGN(fw->len, PAGE_SIZE);
241
242		fw->img = dma_alloc_coherent(fw->device->dev, len, &addr, GFP_KERNEL);
243		if (fw->img) {
244			memcpy(fw->img, src, fw->len);
245			fw->phys = addr;
246		}
247
248		sg_init_one(&fw->mem.sgl, fw->img, len);
249		sg_dma_address(&fw->mem.sgl) = fw->phys;
250		sg_dma_len(&fw->mem.sgl) = len;
251	}
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;
296	default:
297		WARN_ON(1);
298		return -EINVAL;
299	}
300
301	if (!fw->img)
302		return -ENOMEM;
303
304	nvkm_memory_ctor(&nvkm_firmware_mem, &fw->mem.memory);
305	return 0;
306}