aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/firmware_class.c
diff options
context:
space:
mode:
authorStephen Boyd <stephen.boyd@linaro.org>2016-08-02 17:04:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-08-02 19:35:10 -0400
commita098ecd2fa7db8fa4fcc178a43627b29b226edb9 (patch)
tree55c25372dd873c23f00fe32744451cdf49f78f78 /drivers/base/firmware_class.c
parent0e742e927571946e08e877d3629e6efd4891ed95 (diff)
firmware: support loading into a pre-allocated buffer
Some systems are memory constrained but they need to load very large firmwares. The firmware subsystem allows drivers to request this firmware be loaded from the filesystem, but this requires that the entire firmware be loaded into kernel memory first before it's provided to the driver. This can lead to a situation where we map the firmware twice, once to load the firmware into kernel memory and once to copy the firmware into the final resting place. This creates needless memory pressure and delays loading because we have to copy from kernel memory to somewhere else. Let's add a request_firmware_into_buf() API that allows drivers to request firmware be loaded directly into a pre-allocated buffer. This skips the intermediate step of allocating a buffer in kernel memory to hold the firmware image while it's read from the filesystem. It also requires that drivers know how much memory they'll require before requesting the firmware and negates any benefits of firmware caching because the firmware layer doesn't manage the buffer lifetime. For a 16MB buffer, about half the time is spent performing a memcpy from the buffer to the final resting place. I see loading times go from 0.081171 seconds to 0.047696 seconds after applying this patch. Plus the vmalloc pressure is reduced. This is based on a patch from Vikram Mulukutla on codeaurora.org: https://www.codeaurora.org/cgit/quic/la/kernel/msm-3.18/commit/drivers/base/firmware_class.c?h=rel/msm-3.18&id=0a328c5f6cd999f5c591f172216835636f39bcb5 Link: http://lkml.kernel.org/r/20160607164741.31849-4-stephen.boyd@linaro.org Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org> Cc: Mimi Zohar <zohar@linux.vnet.ibm.com> Cc: Vikram Mulukutla <markivx@codeaurora.org> Cc: Mark Brown <broonie@kernel.org> Cc: Ming Lei <ming.lei@canonical.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/base/firmware_class.c')
-rw-r--r--drivers/base/firmware_class.c125
1 files changed, 99 insertions, 26 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 45ed20cefa10..22d1760a4278 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -46,7 +46,8 @@ MODULE_LICENSE("GPL");
46extern struct builtin_fw __start_builtin_fw[]; 46extern struct builtin_fw __start_builtin_fw[];
47extern struct builtin_fw __end_builtin_fw[]; 47extern struct builtin_fw __end_builtin_fw[];
48 48
49static bool fw_get_builtin_firmware(struct firmware *fw, const char *name) 49static bool fw_get_builtin_firmware(struct firmware *fw, const char *name,
50 void *buf, size_t size)
50{ 51{
51 struct builtin_fw *b_fw; 52 struct builtin_fw *b_fw;
52 53
@@ -54,6 +55,9 @@ static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
54 if (strcmp(name, b_fw->name) == 0) { 55 if (strcmp(name, b_fw->name) == 0) {
55 fw->size = b_fw->size; 56 fw->size = b_fw->size;
56 fw->data = b_fw->data; 57 fw->data = b_fw->data;
58
59 if (buf && fw->size <= size)
60 memcpy(buf, fw->data, fw->size);
57 return true; 61 return true;
58 } 62 }
59 } 63 }
@@ -74,7 +78,9 @@ static bool fw_is_builtin_firmware(const struct firmware *fw)
74 78
75#else /* Module case - no builtin firmware support */ 79#else /* Module case - no builtin firmware support */
76 80
77static inline bool fw_get_builtin_firmware(struct firmware *fw, const char *name) 81static inline bool fw_get_builtin_firmware(struct firmware *fw,
82 const char *name, void *buf,
83 size_t size)
78{ 84{
79 return false; 85 return false;
80} 86}
@@ -144,6 +150,7 @@ struct firmware_buf {
144 unsigned long status; 150 unsigned long status;
145 void *data; 151 void *data;
146 size_t size; 152 size_t size;
153 size_t allocated_size;
147#ifdef CONFIG_FW_LOADER_USER_HELPER 154#ifdef CONFIG_FW_LOADER_USER_HELPER
148 bool is_paged_buf; 155 bool is_paged_buf;
149 bool need_uevent; 156 bool need_uevent;
@@ -179,7 +186,8 @@ static DEFINE_MUTEX(fw_lock);
179static struct firmware_cache fw_cache; 186static struct firmware_cache fw_cache;
180 187
181static struct firmware_buf *__allocate_fw_buf(const char *fw_name, 188static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
182 struct firmware_cache *fwc) 189 struct firmware_cache *fwc,
190 void *dbuf, size_t size)
183{ 191{
184 struct firmware_buf *buf; 192 struct firmware_buf *buf;
185 193
@@ -195,6 +203,8 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
195 203
196 kref_init(&buf->ref); 204 kref_init(&buf->ref);
197 buf->fwc = fwc; 205 buf->fwc = fwc;
206 buf->data = dbuf;
207 buf->allocated_size = size;
198 init_completion(&buf->completion); 208 init_completion(&buf->completion);
199#ifdef CONFIG_FW_LOADER_USER_HELPER 209#ifdef CONFIG_FW_LOADER_USER_HELPER
200 INIT_LIST_HEAD(&buf->pending_list); 210 INIT_LIST_HEAD(&buf->pending_list);
@@ -218,7 +228,8 @@ static struct firmware_buf *__fw_lookup_buf(const char *fw_name)
218 228
219static int fw_lookup_and_allocate_buf(const char *fw_name, 229static int fw_lookup_and_allocate_buf(const char *fw_name,
220 struct firmware_cache *fwc, 230 struct firmware_cache *fwc,
221 struct firmware_buf **buf) 231 struct firmware_buf **buf, void *dbuf,
232 size_t size)
222{ 233{
223 struct firmware_buf *tmp; 234 struct firmware_buf *tmp;
224 235
@@ -230,7 +241,7 @@ static int fw_lookup_and_allocate_buf(const char *fw_name,
230 *buf = tmp; 241 *buf = tmp;
231 return 1; 242 return 1;
232 } 243 }
233 tmp = __allocate_fw_buf(fw_name, fwc); 244 tmp = __allocate_fw_buf(fw_name, fwc, dbuf, size);
234 if (tmp) 245 if (tmp)
235 list_add(&tmp->list, &fwc->head); 246 list_add(&tmp->list, &fwc->head);
236 spin_unlock(&fwc->lock); 247 spin_unlock(&fwc->lock);
@@ -262,6 +273,7 @@ static void __fw_free_buf(struct kref *ref)
262 vfree(buf->pages); 273 vfree(buf->pages);
263 } else 274 } else
264#endif 275#endif
276 if (!buf->allocated_size)
265 vfree(buf->data); 277 vfree(buf->data);
266 kfree_const(buf->fw_id); 278 kfree_const(buf->fw_id);
267 kfree(buf); 279 kfree(buf);
@@ -302,13 +314,21 @@ static void fw_finish_direct_load(struct device *device,
302 mutex_unlock(&fw_lock); 314 mutex_unlock(&fw_lock);
303} 315}
304 316
305static int fw_get_filesystem_firmware(struct device *device, 317static int
306 struct firmware_buf *buf) 318fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
307{ 319{
308 loff_t size; 320 loff_t size;
309 int i, len; 321 int i, len;
310 int rc = -ENOENT; 322 int rc = -ENOENT;
311 char *path; 323 char *path;
324 enum kernel_read_file_id id = READING_FIRMWARE;
325 size_t msize = INT_MAX;
326
327 /* Already populated data member means we're loading into a buffer */
328 if (buf->data) {
329 id = READING_FIRMWARE_PREALLOC_BUFFER;
330 msize = buf->allocated_size;
331 }
312 332
313 path = __getname(); 333 path = __getname();
314 if (!path) 334 if (!path)
@@ -327,8 +347,8 @@ static int fw_get_filesystem_firmware(struct device *device,
327 } 347 }
328 348
329 buf->size = 0; 349 buf->size = 0;
330 rc = kernel_read_file_from_path(path, &buf->data, &size, 350 rc = kernel_read_file_from_path(path, &buf->data, &size, msize,
331 INT_MAX, READING_FIRMWARE); 351 id);
332 if (rc) { 352 if (rc) {
333 if (rc == -ENOENT) 353 if (rc == -ENOENT)
334 dev_dbg(device, "loading %s failed with error %d\n", 354 dev_dbg(device, "loading %s failed with error %d\n",
@@ -692,6 +712,15 @@ out:
692 712
693static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); 713static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
694 714
715static void firmware_rw_buf(struct firmware_buf *buf, char *buffer,
716 loff_t offset, size_t count, bool read)
717{
718 if (read)
719 memcpy(buffer, buf->data + offset, count);
720 else
721 memcpy(buf->data + offset, buffer, count);
722}
723
695static void firmware_rw(struct firmware_buf *buf, char *buffer, 724static void firmware_rw(struct firmware_buf *buf, char *buffer,
696 loff_t offset, size_t count, bool read) 725 loff_t offset, size_t count, bool read)
697{ 726{
@@ -739,7 +768,10 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
739 768
740 ret_count = count; 769 ret_count = count;
741 770
742 firmware_rw(buf, buffer, offset, count, true); 771 if (buf->data)
772 firmware_rw_buf(buf, buffer, offset, count, true);
773 else
774 firmware_rw(buf, buffer, offset, count, true);
743 775
744out: 776out:
745 mutex_unlock(&fw_lock); 777 mutex_unlock(&fw_lock);
@@ -815,12 +847,21 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
815 goto out; 847 goto out;
816 } 848 }
817 849
818 retval = fw_realloc_buffer(fw_priv, offset + count); 850 if (buf->data) {
819 if (retval) 851 if (offset + count > buf->allocated_size) {
820 goto out; 852 retval = -ENOMEM;
853 goto out;
854 }
855 firmware_rw_buf(buf, buffer, offset, count, false);
856 retval = count;
857 } else {
858 retval = fw_realloc_buffer(fw_priv, offset + count);
859 if (retval)
860 goto out;
821 861
822 retval = count; 862 retval = count;
823 firmware_rw(buf, buffer, offset, count, false); 863 firmware_rw(buf, buffer, offset, count, false);
864 }
824 865
825 buf->size = max_t(size_t, offset + count, buf->size); 866 buf->size = max_t(size_t, offset + count, buf->size);
826out: 867out:
@@ -890,7 +931,8 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
890 struct firmware_buf *buf = fw_priv->buf; 931 struct firmware_buf *buf = fw_priv->buf;
891 932
892 /* fall back on userspace loading */ 933 /* fall back on userspace loading */
893 buf->is_paged_buf = true; 934 if (!buf->data)
935 buf->is_paged_buf = true;
894 936
895 dev_set_uevent_suppress(f_dev, true); 937 dev_set_uevent_suppress(f_dev, true);
896 938
@@ -925,7 +967,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
925 967
926 if (is_fw_load_aborted(buf)) 968 if (is_fw_load_aborted(buf))
927 retval = -EAGAIN; 969 retval = -EAGAIN;
928 else if (!buf->data) 970 else if (buf->is_paged_buf && !buf->data)
929 retval = -ENOMEM; 971 retval = -ENOMEM;
930 972
931 device_del(f_dev); 973 device_del(f_dev);
@@ -1008,7 +1050,7 @@ static int sync_cached_firmware_buf(struct firmware_buf *buf)
1008 */ 1050 */
1009static int 1051static int
1010_request_firmware_prepare(struct firmware **firmware_p, const char *name, 1052_request_firmware_prepare(struct firmware **firmware_p, const char *name,
1011 struct device *device) 1053 struct device *device, void *dbuf, size_t size)
1012{ 1054{
1013 struct firmware *firmware; 1055 struct firmware *firmware;
1014 struct firmware_buf *buf; 1056 struct firmware_buf *buf;
@@ -1021,12 +1063,12 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
1021 return -ENOMEM; 1063 return -ENOMEM;
1022 } 1064 }
1023 1065
1024 if (fw_get_builtin_firmware(firmware, name)) { 1066 if (fw_get_builtin_firmware(firmware, name, dbuf, size)) {
1025 dev_dbg(device, "using built-in %s\n", name); 1067 dev_dbg(device, "using built-in %s\n", name);
1026 return 0; /* assigned */ 1068 return 0; /* assigned */
1027 } 1069 }
1028 1070
1029 ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf); 1071 ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size);
1030 1072
1031 /* 1073 /*
1032 * bind with 'buf' now to avoid warning in failure path 1074 * bind with 'buf' now to avoid warning in failure path
@@ -1089,7 +1131,8 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
1089/* called from request_firmware() and request_firmware_work_func() */ 1131/* called from request_firmware() and request_firmware_work_func() */
1090static int 1132static int
1091_request_firmware(const struct firmware **firmware_p, const char *name, 1133_request_firmware(const struct firmware **firmware_p, const char *name,
1092 struct device *device, unsigned int opt_flags) 1134 struct device *device, void *buf, size_t size,
1135 unsigned int opt_flags)
1093{ 1136{
1094 struct firmware *fw = NULL; 1137 struct firmware *fw = NULL;
1095 long timeout; 1138 long timeout;
@@ -1103,7 +1146,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
1103 goto out; 1146 goto out;
1104 } 1147 }
1105 1148
1106 ret = _request_firmware_prepare(&fw, name, device); 1149 ret = _request_firmware_prepare(&fw, name, device, buf, size);
1107 if (ret <= 0) /* error or already assigned */ 1150 if (ret <= 0) /* error or already assigned */
1108 goto out; 1151 goto out;
1109 1152
@@ -1182,7 +1225,7 @@ request_firmware(const struct firmware **firmware_p, const char *name,
1182 1225
1183 /* Need to pin this module until return */ 1226 /* Need to pin this module until return */
1184 __module_get(THIS_MODULE); 1227 __module_get(THIS_MODULE);
1185 ret = _request_firmware(firmware_p, name, device, 1228 ret = _request_firmware(firmware_p, name, device, NULL, 0,
1186 FW_OPT_UEVENT | FW_OPT_FALLBACK); 1229 FW_OPT_UEVENT | FW_OPT_FALLBACK);
1187 module_put(THIS_MODULE); 1230 module_put(THIS_MODULE);
1188 return ret; 1231 return ret;
@@ -1206,7 +1249,7 @@ int request_firmware_direct(const struct firmware **firmware_p,
1206 int ret; 1249 int ret;
1207 1250
1208 __module_get(THIS_MODULE); 1251 __module_get(THIS_MODULE);
1209 ret = _request_firmware(firmware_p, name, device, 1252 ret = _request_firmware(firmware_p, name, device, NULL, 0,
1210 FW_OPT_UEVENT | FW_OPT_NO_WARN); 1253 FW_OPT_UEVENT | FW_OPT_NO_WARN);
1211 module_put(THIS_MODULE); 1254 module_put(THIS_MODULE);
1212 return ret; 1255 return ret;
@@ -1214,6 +1257,36 @@ int request_firmware_direct(const struct firmware **firmware_p,
1214EXPORT_SYMBOL_GPL(request_firmware_direct); 1257EXPORT_SYMBOL_GPL(request_firmware_direct);
1215 1258
1216/** 1259/**
1260 * request_firmware_into_buf - load firmware into a previously allocated buffer
1261 * @firmware_p: pointer to firmware image
1262 * @name: name of firmware file
1263 * @device: device for which firmware is being loaded and DMA region allocated
1264 * @buf: address of buffer to load firmware into
1265 * @size: size of buffer
1266 *
1267 * This function works pretty much like request_firmware(), but it doesn't
1268 * allocate a buffer to hold the firmware data. Instead, the firmware
1269 * is loaded directly into the buffer pointed to by @buf and the @firmware_p
1270 * data member is pointed at @buf.
1271 *
1272 * This function doesn't cache firmware either.
1273 */
1274int
1275request_firmware_into_buf(const struct firmware **firmware_p, const char *name,
1276 struct device *device, void *buf, size_t size)
1277{
1278 int ret;
1279
1280 __module_get(THIS_MODULE);
1281 ret = _request_firmware(firmware_p, name, device, buf, size,
1282 FW_OPT_UEVENT | FW_OPT_FALLBACK |
1283 FW_OPT_NOCACHE);
1284 module_put(THIS_MODULE);
1285 return ret;
1286}
1287EXPORT_SYMBOL(request_firmware_into_buf);
1288
1289/**
1217 * release_firmware: - release the resource associated with a firmware image 1290 * release_firmware: - release the resource associated with a firmware image
1218 * @fw: firmware resource to release 1291 * @fw: firmware resource to release
1219 **/ 1292 **/
@@ -1245,7 +1318,7 @@ static void request_firmware_work_func(struct work_struct *work)
1245 1318
1246 fw_work = container_of(work, struct firmware_work, work); 1319 fw_work = container_of(work, struct firmware_work, work);
1247 1320
1248 _request_firmware(&fw, fw_work->name, fw_work->device, 1321 _request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0,
1249 fw_work->opt_flags); 1322 fw_work->opt_flags);
1250 fw_work->cont(fw, fw_work->context); 1323 fw_work->cont(fw, fw_work->context);
1251 put_device(fw_work->device); /* taken in request_firmware_nowait() */ 1324 put_device(fw_work->device); /* taken in request_firmware_nowait() */
@@ -1378,7 +1451,7 @@ static int uncache_firmware(const char *fw_name)
1378 1451
1379 pr_debug("%s: %s\n", __func__, fw_name); 1452 pr_debug("%s: %s\n", __func__, fw_name);
1380 1453
1381 if (fw_get_builtin_firmware(&fw, fw_name)) 1454 if (fw_get_builtin_firmware(&fw, fw_name, NULL, 0))
1382 return 0; 1455 return 0;
1383 1456
1384 buf = fw_lookup_buf(fw_name); 1457 buf = fw_lookup_buf(fw_name);