aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2012-08-20 07:04:16 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-06 17:46:16 -0400
commitac39b3ea73aacde876d1d5ee1ca3e2719f771482 (patch)
tree58b9ee67654ea41ddba770f827d7f949ee1d40f2 /drivers/base
parentef40bb1bd01738670bd567e3dce8e862f2b91bf3 (diff)
firmware loader: let caching firmware piggyback on loading firmware
After starting caching firmware, there is still some time left before devices are suspended, during the period, request_firmware or its nowait version may still be triggered by the below situations to load firmware images which can't be cached during suspend/resume cycle. - new devices added - driver bind - or device open kind of things This patch utilizes the piggyback trick to cache firmware for this kind of situation: just increase the firmware buf's reference count and add the fw name entry into cache entry list after starting caching firmware and before syscore_suspend() is called. Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/firmware_class.c83
1 files changed, 74 insertions, 9 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index edc88bc68b3d..95f6851b3010 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -25,6 +25,7 @@
25#include <linux/async.h> 25#include <linux/async.h>
26#include <linux/pm.h> 26#include <linux/pm.h>
27#include <linux/suspend.h> 27#include <linux/suspend.h>
28#include <linux/syscore_ops.h>
28 29
29#include "base.h" 30#include "base.h"
30 31
@@ -105,6 +106,8 @@ struct firmware_cache {
105 spinlock_t name_lock; 106 spinlock_t name_lock;
106 struct list_head fw_names; 107 struct list_head fw_names;
107 108
109 int state;
110
108 wait_queue_head_t wait_queue; 111 wait_queue_head_t wait_queue;
109 int cnt; 112 int cnt;
110 struct delayed_work work; 113 struct delayed_work work;
@@ -146,6 +149,11 @@ struct fw_name_devm {
146 149
147#define to_fwbuf(d) container_of(d, struct firmware_buf, ref) 150#define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
148 151
152#define FW_LOADER_NO_CACHE 0
153#define FW_LOADER_START_CACHE 1
154
155static int fw_cache_piggyback_on_request(const char *name);
156
149/* fw_lock could be moved to 'struct firmware_priv' but since it is just 157/* fw_lock could be moved to 'struct firmware_priv' but since it is just
150 * guarding for corner cases a global lock should be OK */ 158 * guarding for corner cases a global lock should be OK */
151static DEFINE_MUTEX(fw_lock); 159static DEFINE_MUTEX(fw_lock);
@@ -741,6 +749,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
741 int retval = 0; 749 int retval = 0;
742 struct device *f_dev = &fw_priv->dev; 750 struct device *f_dev = &fw_priv->dev;
743 struct firmware_buf *buf = fw_priv->buf; 751 struct firmware_buf *buf = fw_priv->buf;
752 struct firmware_cache *fwc = &fw_cache;
744 753
745 dev_set_uevent_suppress(f_dev, true); 754 dev_set_uevent_suppress(f_dev, true);
746 755
@@ -796,6 +805,15 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
796 if (!retval) 805 if (!retval)
797 retval = fw_map_pages_buf(buf); 806 retval = fw_map_pages_buf(buf);
798 807
808 /*
809 * After caching firmware image is started, let it piggyback
810 * on request firmware.
811 */
812 if (!retval && fwc->state == FW_LOADER_START_CACHE) {
813 if (fw_cache_piggyback_on_request(buf->fw_id))
814 kref_get(&buf->ref);
815 }
816
799 /* pass the pages buffer to driver at the last minute */ 817 /* pass the pages buffer to driver at the last minute */
800 fw_set_page_data(buf, fw_priv->fw); 818 fw_set_page_data(buf, fw_priv->fw);
801 819
@@ -1041,6 +1059,29 @@ exit:
1041 return fce; 1059 return fce;
1042} 1060}
1043 1061
1062static int fw_cache_piggyback_on_request(const char *name)
1063{
1064 struct firmware_cache *fwc = &fw_cache;
1065 struct fw_cache_entry *fce;
1066 int ret = 0;
1067
1068 spin_lock(&fwc->name_lock);
1069 list_for_each_entry(fce, &fwc->fw_names, list) {
1070 if (!strcmp(fce->name, name))
1071 goto found;
1072 }
1073
1074 fce = alloc_fw_cache_entry(name);
1075 if (fce) {
1076 ret = 1;
1077 list_add(&fce->list, &fwc->fw_names);
1078 pr_debug("%s: fw: %s\n", __func__, name);
1079 }
1080found:
1081 spin_unlock(&fwc->name_lock);
1082 return ret;
1083}
1084
1044static void free_fw_cache_entry(struct fw_cache_entry *fce) 1085static void free_fw_cache_entry(struct fw_cache_entry *fce)
1045{ 1086{
1046 kfree(fce); 1087 kfree(fce);
@@ -1054,17 +1095,14 @@ static void __async_dev_cache_fw_image(void *fw_entry,
1054 int ret; 1095 int ret;
1055 1096
1056 ret = cache_firmware(fce->name); 1097 ret = cache_firmware(fce->name);
1057 if (ret) 1098 if (ret) {
1058 goto free; 1099 spin_lock(&fwc->name_lock);
1100 list_del(&fce->list);
1101 spin_unlock(&fwc->name_lock);
1059 1102
1060 spin_lock(&fwc->name_lock); 1103 free_fw_cache_entry(fce);
1061 list_add(&fce->list, &fwc->fw_names); 1104 }
1062 spin_unlock(&fwc->name_lock);
1063 goto drop_ref;
1064 1105
1065free:
1066 free_fw_cache_entry(fce);
1067drop_ref:
1068 spin_lock(&fwc->name_lock); 1106 spin_lock(&fwc->name_lock);
1069 fwc->cnt--; 1107 fwc->cnt--;
1070 spin_unlock(&fwc->name_lock); 1108 spin_unlock(&fwc->name_lock);
@@ -1109,6 +1147,7 @@ static void dev_cache_fw_image(struct device *dev, void *data)
1109 1147
1110 spin_lock(&fwc->name_lock); 1148 spin_lock(&fwc->name_lock);
1111 fwc->cnt++; 1149 fwc->cnt++;
1150 list_add(&fce->list, &fwc->fw_names);
1112 spin_unlock(&fwc->name_lock); 1151 spin_unlock(&fwc->name_lock);
1113 1152
1114 async_schedule(__async_dev_cache_fw_image, (void *)fce); 1153 async_schedule(__async_dev_cache_fw_image, (void *)fce);
@@ -1164,7 +1203,10 @@ static void device_cache_fw_images(void)
1164 old_timeout = loading_timeout; 1203 old_timeout = loading_timeout;
1165 loading_timeout = 10; 1204 loading_timeout = 10;
1166 1205
1206 mutex_lock(&fw_lock);
1207 fwc->state = FW_LOADER_START_CACHE;
1167 dpm_for_each_dev(NULL, dev_cache_fw_image); 1208 dpm_for_each_dev(NULL, dev_cache_fw_image);
1209 mutex_unlock(&fw_lock);
1168 1210
1169 /* wait for completion of caching firmware for all devices */ 1211 /* wait for completion of caching firmware for all devices */
1170 spin_lock(&fwc->name_lock); 1212 spin_lock(&fwc->name_lock);
@@ -1229,6 +1271,14 @@ static int fw_pm_notify(struct notifier_block *notify_block,
1229 case PM_POST_SUSPEND: 1271 case PM_POST_SUSPEND:
1230 case PM_POST_HIBERNATION: 1272 case PM_POST_HIBERNATION:
1231 case PM_POST_RESTORE: 1273 case PM_POST_RESTORE:
1274 /*
1275 * In case that system sleep failed and syscore_suspend is
1276 * not called.
1277 */
1278 mutex_lock(&fw_lock);
1279 fw_cache.state = FW_LOADER_NO_CACHE;
1280 mutex_unlock(&fw_lock);
1281
1232 device_uncache_fw_images_delay(10 * MSEC_PER_SEC); 1282 device_uncache_fw_images_delay(10 * MSEC_PER_SEC);
1233 break; 1283 break;
1234 } 1284 }
@@ -1243,6 +1293,17 @@ static int fw_pm_notify(struct notifier_block *notify_block,
1243} 1293}
1244#endif 1294#endif
1245 1295
1296/* stop caching firmware once syscore_suspend is reached */
1297static int fw_suspend(void)
1298{
1299 fw_cache.state = FW_LOADER_NO_CACHE;
1300 return 0;
1301}
1302
1303static struct syscore_ops fw_syscore_ops = {
1304 .suspend = fw_suspend,
1305};
1306
1246static void __init fw_cache_init(void) 1307static void __init fw_cache_init(void)
1247{ 1308{
1248 spin_lock_init(&fw_cache.lock); 1309 spin_lock_init(&fw_cache.lock);
@@ -1251,6 +1312,7 @@ static void __init fw_cache_init(void)
1251 spin_lock_init(&fw_cache.name_lock); 1312 spin_lock_init(&fw_cache.name_lock);
1252 INIT_LIST_HEAD(&fw_cache.fw_names); 1313 INIT_LIST_HEAD(&fw_cache.fw_names);
1253 fw_cache.cnt = 0; 1314 fw_cache.cnt = 0;
1315 fw_cache.state = FW_LOADER_NO_CACHE;
1254 1316
1255 init_waitqueue_head(&fw_cache.wait_queue); 1317 init_waitqueue_head(&fw_cache.wait_queue);
1256 INIT_DELAYED_WORK(&fw_cache.work, 1318 INIT_DELAYED_WORK(&fw_cache.work,
@@ -1258,6 +1320,8 @@ static void __init fw_cache_init(void)
1258 1320
1259 fw_cache.pm_notify.notifier_call = fw_pm_notify; 1321 fw_cache.pm_notify.notifier_call = fw_pm_notify;
1260 register_pm_notifier(&fw_cache.pm_notify); 1322 register_pm_notifier(&fw_cache.pm_notify);
1323
1324 register_syscore_ops(&fw_syscore_ops);
1261} 1325}
1262 1326
1263static int __init firmware_class_init(void) 1327static int __init firmware_class_init(void)
@@ -1268,6 +1332,7 @@ static int __init firmware_class_init(void)
1268 1332
1269static void __exit firmware_class_exit(void) 1333static void __exit firmware_class_exit(void)
1270{ 1334{
1335 unregister_syscore_ops(&fw_syscore_ops);
1271 unregister_pm_notifier(&fw_cache.pm_notify); 1336 unregister_pm_notifier(&fw_cache.pm_notify);
1272 class_unregister(&firmware_class); 1337 class_unregister(&firmware_class);
1273} 1338}