aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/firmware_class.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2012-08-04 00:01:27 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-16 16:44:44 -0400
commit37276a51f803ef63be988e26293ac85188475556 (patch)
tree86c3daf910f4eb175d42c94e9bb58a9840d366e3 /drivers/base/firmware_class.c
parentbddb1b9078505bb0e430c87c5015c0963f7a594f (diff)
firmware: introduce device_cache/uncache_fw_images
This patch introduces the three helpers below: void device_cache_fw_images(void) void device_uncache_fw_images(void) void device_uncache_fw_images_delay(unsigned long) so we can use device_cache_fw_images() to cache firmware for all devices which need firmware to work, and the device driver can get the firmware easily from kernel memory when system isn't ready for completing requests of loading firmware. After system is ready for completing firmware loading, driver core will call device_uncache_fw_images() or its delay version to free the cached firmware. The above helpers will be used to cache device firmware during system suspend/resume cycle in the following patches. Signed-off-by: Ming Lei <ming.lei@canonical.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/firmware_class.c')
-rw-r--r--drivers/base/firmware_class.c221
1 files changed, 215 insertions, 6 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 65c60666685b..68fd4c698c77 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -22,6 +22,11 @@
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <linux/sched.h> 23#include <linux/sched.h>
24#include <linux/list.h> 24#include <linux/list.h>
25#include <linux/async.h>
26#include <linux/pm.h>
27
28#include "base.h"
29#include "power/power.h"
25 30
26MODULE_AUTHOR("Manuel Estrada Sainz"); 31MODULE_AUTHOR("Manuel Estrada Sainz");
27MODULE_DESCRIPTION("Multi purpose firmware loading support"); 32MODULE_DESCRIPTION("Multi purpose firmware loading support");
@@ -90,6 +95,19 @@ struct firmware_cache {
90 /* firmware_buf instance will be added into the below list */ 95 /* firmware_buf instance will be added into the below list */
91 spinlock_t lock; 96 spinlock_t lock;
92 struct list_head head; 97 struct list_head head;
98
99 /*
100 * Names of firmware images which have been cached successfully
101 * will be added into the below list so that device uncache
102 * helper can trace which firmware images have been cached
103 * before.
104 */
105 spinlock_t name_lock;
106 struct list_head fw_names;
107
108 wait_queue_head_t wait_queue;
109 int cnt;
110 struct delayed_work work;
93}; 111};
94 112
95struct firmware_buf { 113struct firmware_buf {
@@ -106,6 +124,11 @@ struct firmware_buf {
106 char fw_id[]; 124 char fw_id[];
107}; 125};
108 126
127struct fw_cache_entry {
128 struct list_head list;
129 char name[];
130};
131
109struct firmware_priv { 132struct firmware_priv {
110 struct timer_list timeout; 133 struct timer_list timeout;
111 bool nowait; 134 bool nowait;
@@ -220,12 +243,6 @@ static void fw_free_buf(struct firmware_buf *buf)
220 kref_put(&buf->ref, __fw_free_buf); 243 kref_put(&buf->ref, __fw_free_buf);
221} 244}
222 245
223static void __init fw_cache_init(void)
224{
225 spin_lock_init(&fw_cache.lock);
226 INIT_LIST_HEAD(&fw_cache.head);
227}
228
229static struct firmware_priv *to_firmware_priv(struct device *dev) 246static struct firmware_priv *to_firmware_priv(struct device *dev)
230{ 247{
231 return container_of(dev, struct firmware_priv, dev); 248 return container_of(dev, struct firmware_priv, dev);
@@ -1008,6 +1025,198 @@ int uncache_firmware(const char *fw_name)
1008 return -EINVAL; 1025 return -EINVAL;
1009} 1026}
1010 1027
1028static struct fw_cache_entry *alloc_fw_cache_entry(const char *name)
1029{
1030 struct fw_cache_entry *fce;
1031
1032 fce = kzalloc(sizeof(*fce) + strlen(name) + 1, GFP_ATOMIC);
1033 if (!fce)
1034 goto exit;
1035
1036 strcpy(fce->name, name);
1037exit:
1038 return fce;
1039}
1040
1041static void free_fw_cache_entry(struct fw_cache_entry *fce)
1042{
1043 kfree(fce);
1044}
1045
1046static void __async_dev_cache_fw_image(void *fw_entry,
1047 async_cookie_t cookie)
1048{
1049 struct fw_cache_entry *fce = fw_entry;
1050 struct firmware_cache *fwc = &fw_cache;
1051 int ret;
1052
1053 ret = cache_firmware(fce->name);
1054 if (ret)
1055 goto free;
1056
1057 spin_lock(&fwc->name_lock);
1058 list_add(&fce->list, &fwc->fw_names);
1059 spin_unlock(&fwc->name_lock);
1060 goto drop_ref;
1061
1062free:
1063 free_fw_cache_entry(fce);
1064drop_ref:
1065 spin_lock(&fwc->name_lock);
1066 fwc->cnt--;
1067 spin_unlock(&fwc->name_lock);
1068
1069 wake_up(&fwc->wait_queue);
1070}
1071
1072/* called with dev->devres_lock held */
1073static void dev_create_fw_entry(struct device *dev, void *res,
1074 void *data)
1075{
1076 struct fw_name_devm *fwn = res;
1077 const char *fw_name = fwn->name;
1078 struct list_head *head = data;
1079 struct fw_cache_entry *fce;
1080
1081 fce = alloc_fw_cache_entry(fw_name);
1082 if (fce)
1083 list_add(&fce->list, head);
1084}
1085
1086static int devm_name_match(struct device *dev, void *res,
1087 void *match_data)
1088{
1089 struct fw_name_devm *fwn = res;
1090 return (fwn->magic == (unsigned long)match_data);
1091}
1092
1093static void dev_cache_fw_image(struct device *dev)
1094{
1095 LIST_HEAD(todo);
1096 struct fw_cache_entry *fce;
1097 struct fw_cache_entry *fce_next;
1098 struct firmware_cache *fwc = &fw_cache;
1099
1100 devres_for_each_res(dev, fw_name_devm_release,
1101 devm_name_match, &fw_cache,
1102 dev_create_fw_entry, &todo);
1103
1104 list_for_each_entry_safe(fce, fce_next, &todo, list) {
1105 list_del(&fce->list);
1106
1107 spin_lock(&fwc->name_lock);
1108 fwc->cnt++;
1109 spin_unlock(&fwc->name_lock);
1110
1111 async_schedule(__async_dev_cache_fw_image, (void *)fce);
1112 }
1113}
1114
1115static void __device_uncache_fw_images(void)
1116{
1117 struct firmware_cache *fwc = &fw_cache;
1118 struct fw_cache_entry *fce;
1119
1120 spin_lock(&fwc->name_lock);
1121 while (!list_empty(&fwc->fw_names)) {
1122 fce = list_entry(fwc->fw_names.next,
1123 struct fw_cache_entry, list);
1124 list_del(&fce->list);
1125 spin_unlock(&fwc->name_lock);
1126
1127 uncache_firmware(fce->name);
1128 free_fw_cache_entry(fce);
1129
1130 spin_lock(&fwc->name_lock);
1131 }
1132 spin_unlock(&fwc->name_lock);
1133}
1134
1135/**
1136 * device_cache_fw_images - cache devices' firmware
1137 *
1138 * If one device called request_firmware or its nowait version
1139 * successfully before, the firmware names are recored into the
1140 * device's devres link list, so device_cache_fw_images can call
1141 * cache_firmware() to cache these firmwares for the device,
1142 * then the device driver can load its firmwares easily at
1143 * time when system is not ready to complete loading firmware.
1144 */
1145static void device_cache_fw_images(void)
1146{
1147 struct firmware_cache *fwc = &fw_cache;
1148 struct device *dev;
1149 DEFINE_WAIT(wait);
1150
1151 pr_debug("%s\n", __func__);
1152
1153 device_pm_lock();
1154 list_for_each_entry(dev, &dpm_list, power.entry)
1155 dev_cache_fw_image(dev);
1156 device_pm_unlock();
1157
1158 /* wait for completion of caching firmware for all devices */
1159 spin_lock(&fwc->name_lock);
1160 for (;;) {
1161 prepare_to_wait(&fwc->wait_queue, &wait,
1162 TASK_UNINTERRUPTIBLE);
1163 if (!fwc->cnt)
1164 break;
1165
1166 spin_unlock(&fwc->name_lock);
1167
1168 schedule();
1169
1170 spin_lock(&fwc->name_lock);
1171 }
1172 spin_unlock(&fwc->name_lock);
1173 finish_wait(&fwc->wait_queue, &wait);
1174}
1175
1176/**
1177 * device_uncache_fw_images - uncache devices' firmware
1178 *
1179 * uncache all firmwares which have been cached successfully
1180 * by device_uncache_fw_images earlier
1181 */
1182static void device_uncache_fw_images(void)
1183{
1184 pr_debug("%s\n", __func__);
1185 __device_uncache_fw_images();
1186}
1187
1188static void device_uncache_fw_images_work(struct work_struct *work)
1189{
1190 device_uncache_fw_images();
1191}
1192
1193/**
1194 * device_uncache_fw_images_delay - uncache devices firmwares
1195 * @delay: number of milliseconds to delay uncache device firmwares
1196 *
1197 * uncache all devices's firmwares which has been cached successfully
1198 * by device_cache_fw_images after @delay milliseconds.
1199 */
1200static void device_uncache_fw_images_delay(unsigned long delay)
1201{
1202 schedule_delayed_work(&fw_cache.work,
1203 msecs_to_jiffies(delay));
1204}
1205
1206static void __init fw_cache_init(void)
1207{
1208 spin_lock_init(&fw_cache.lock);
1209 INIT_LIST_HEAD(&fw_cache.head);
1210
1211 spin_lock_init(&fw_cache.name_lock);
1212 INIT_LIST_HEAD(&fw_cache.fw_names);
1213 fw_cache.cnt = 0;
1214
1215 init_waitqueue_head(&fw_cache.wait_queue);
1216 INIT_DELAYED_WORK(&fw_cache.work,
1217 device_uncache_fw_images_work);
1218}
1219
1011static int __init firmware_class_init(void) 1220static int __init firmware_class_init(void)
1012{ 1221{
1013 fw_cache_init(); 1222 fw_cache_init();