1 /* $NetBSD: nouveau_nvkm_core_firmware.c,v 1.2 2021/12/18 23:45:34 riastradh Exp $ */
2
3 /*
4 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24 #include <sys/cdefs.h>
25 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_core_firmware.c,v 1.2 2021/12/18 23:45:34 riastradh Exp $");
26
27 #include <core/device.h>
28 #include <core/firmware.h>
29
30 int
nvkm_firmware_load_name(const struct nvkm_subdev * subdev,const char * base,const char * name,int ver,const struct firmware ** pfw)31 nvkm_firmware_load_name(const struct nvkm_subdev *subdev, const char *base,
32 const char *name, int ver, const struct firmware **pfw)
33 {
34 char path[64];
35 int ret;
36
37 snprintf(path, sizeof(path), "%s%s", base, name);
38 ret = nvkm_firmware_get(subdev, path, ver, pfw);
39 if (ret < 0)
40 return ret;
41
42 return 0;
43 }
44
45 int
nvkm_firmware_load_blob(const struct nvkm_subdev * subdev,const char * base,const char * name,int ver,struct nvkm_blob * blob)46 nvkm_firmware_load_blob(const struct nvkm_subdev *subdev, const char *base,
47 const char *name, int ver, struct nvkm_blob *blob)
48 {
49 const struct firmware *fw;
50 int ret;
51
52 ret = nvkm_firmware_load_name(subdev, base, name, ver, &fw);
53 if (ret == 0) {
54 blob->data = kmemdup(fw->data, fw->size, GFP_KERNEL);
55 blob->size = fw->size;
56 nvkm_firmware_put(fw);
57 if (!blob->data)
58 return -ENOMEM;
59 }
60
61 return ret;
62 }
63
64 /**
65 * nvkm_firmware_get - load firmware from the official nvidia/chip/ directory
66 * @subdev subdevice that will use that firmware
67 * @fwname name of firmware file to load
68 * @fw firmware structure to load to
69 *
70 * Use this function to load firmware files in the form nvidia/chip/fwname.bin.
71 * Firmware files released by NVIDIA will always follow this format.
72 */
73 int
nvkm_firmware_get(const struct nvkm_subdev * subdev,const char * fwname,int ver,const struct firmware ** fw)74 nvkm_firmware_get(const struct nvkm_subdev *subdev, const char *fwname, int ver,
75 const struct firmware **fw)
76 {
77 struct nvkm_device *device = subdev->device;
78 char f[64];
79 char cname[16];
80 int i;
81
82 /* Convert device name to lowercase */
83 strncpy(cname, device->chip->name, sizeof(cname));
84 cname[sizeof(cname) - 1] = '\0';
85 i = strlen(cname);
86 while (i) {
87 --i;
88 cname[i] = tolower(cname[i]);
89 }
90
91 if (ver != 0)
92 snprintf(f, sizeof(f), "nvidia/%s/%s-%d.bin", cname, fwname, ver);
93 else
94 snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname);
95
96 if (!firmware_request_nowarn(fw, f, device->dev)) {
97 nvkm_debug(subdev, "firmware \"%s\" loaded - %zu byte(s)\n",
98 f, (*fw)->size);
99 return 0;
100 }
101
102 nvkm_debug(subdev, "firmware \"%s\" unavailable\n", f);
103 return -ENOENT;
104 }
105
106 /**
107 * nvkm_firmware_put - release firmware loaded with nvkm_firmware_get
108 */
109 void
nvkm_firmware_put(const struct firmware * fw)110 nvkm_firmware_put(const struct firmware *fw)
111 {
112 release_firmware(fw);
113 }
114