aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/firmware_class.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2012-10-09 00:01:01 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-22 11:37:16 -0400
commit373304fe10fc46e68815c7116709ad292695dfd1 (patch)
treee81c57ff5959628e61e93ff62f13a1b5151cd1b7 /drivers/base/firmware_class.c
parent6f0c0580b70c89094b3422ba81118c7b959c7556 (diff)
firmware loader: cancel uncache work before caching firmware
Under 'Opportunistic sleep' situation, system sleep might be triggered very frequently, so the uncahce work may not be completed before caching firmware during next suspend. This patch cancels the uncache work before caching firmware to fix the problem above. Also this patch optimizes the cacheing firmware mechanism a bit by only storing one firmware cache entry for one firmware image. So if the firmware is still cached during suspend, it doesn't need to be loaded from user space any more. Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/firmware_class.c')
-rw-r--r--drivers/base/firmware_class.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 81541452887b..d06a8d0534bf 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -1142,17 +1142,27 @@ exit:
1142 return fce; 1142 return fce;
1143} 1143}
1144 1144
1145static int fw_cache_piggyback_on_request(const char *name) 1145static int __fw_entry_found(const char *name)
1146{ 1146{
1147 struct firmware_cache *fwc = &fw_cache; 1147 struct firmware_cache *fwc = &fw_cache;
1148 struct fw_cache_entry *fce; 1148 struct fw_cache_entry *fce;
1149 int ret = 0;
1150 1149
1151 spin_lock(&fwc->name_lock);
1152 list_for_each_entry(fce, &fwc->fw_names, list) { 1150 list_for_each_entry(fce, &fwc->fw_names, list) {
1153 if (!strcmp(fce->name, name)) 1151 if (!strcmp(fce->name, name))
1154 goto found; 1152 return 1;
1155 } 1153 }
1154 return 0;
1155}
1156
1157static int fw_cache_piggyback_on_request(const char *name)
1158{
1159 struct firmware_cache *fwc = &fw_cache;
1160 struct fw_cache_entry *fce;
1161 int ret = 0;
1162
1163 spin_lock(&fwc->name_lock);
1164 if (__fw_entry_found(name))
1165 goto found;
1156 1166
1157 fce = alloc_fw_cache_entry(name); 1167 fce = alloc_fw_cache_entry(name);
1158 if (fce) { 1168 if (fce) {
@@ -1229,11 +1239,19 @@ static void dev_cache_fw_image(struct device *dev, void *data)
1229 list_del(&fce->list); 1239 list_del(&fce->list);
1230 1240
1231 spin_lock(&fwc->name_lock); 1241 spin_lock(&fwc->name_lock);
1232 fwc->cnt++; 1242 /* only one cache entry for one firmware */
1233 list_add(&fce->list, &fwc->fw_names); 1243 if (!__fw_entry_found(fce->name)) {
1244 fwc->cnt++;
1245 list_add(&fce->list, &fwc->fw_names);
1246 } else {
1247 free_fw_cache_entry(fce);
1248 fce = NULL;
1249 }
1234 spin_unlock(&fwc->name_lock); 1250 spin_unlock(&fwc->name_lock);
1235 1251
1236 async_schedule(__async_dev_cache_fw_image, (void *)fce); 1252 if (fce)
1253 async_schedule(__async_dev_cache_fw_image,
1254 (void *)fce);
1237 } 1255 }
1238} 1256}
1239 1257
@@ -1275,6 +1293,9 @@ static void device_cache_fw_images(void)
1275 1293
1276 pr_debug("%s\n", __func__); 1294 pr_debug("%s\n", __func__);
1277 1295
1296 /* cancel uncache work */
1297 cancel_delayed_work_sync(&fwc->work);
1298
1278 /* 1299 /*
1279 * use small loading timeout for caching devices' firmware 1300 * use small loading timeout for caching devices' firmware
1280 * because all these firmware images have been loaded 1301 * because all these firmware images have been loaded