@@ -1132,6 +1132,7 @@ EXPORT_SYMBOL(release_firmware);
11321132/* Async support */
11331133struct firmware_work {
11341134 struct work_struct work ;
1135+ struct list_head list ;
11351136 struct module * module ;
11361137 const char * name ;
11371138 struct device * device ;
@@ -1140,6 +1141,17 @@ struct firmware_work {
11401141 u32 opt_flags ;
11411142};
11421143
1144+ static LIST_HEAD (firmware_work_list );
1145+ static DEFINE_SPINLOCK (firmware_work_lock );
1146+
1147+ static void firmware_work_free (struct firmware_work * fw_work )
1148+ {
1149+ put_device (fw_work -> device ); /* taken in request_firmware_nowait() */
1150+ module_put (fw_work -> module );
1151+ kfree_const (fw_work -> name );
1152+ kfree (fw_work );
1153+ }
1154+
11431155static void request_firmware_work_func (struct work_struct * work )
11441156{
11451157 struct firmware_work * fw_work ;
@@ -1150,11 +1162,15 @@ static void request_firmware_work_func(struct work_struct *work)
11501162 _request_firmware (& fw , fw_work -> name , fw_work -> device , NULL , 0 , 0 ,
11511163 fw_work -> opt_flags );
11521164 fw_work -> cont (fw , fw_work -> context );
1153- put_device (fw_work -> device ); /* taken in request_firmware_nowait() */
11541165
1155- module_put (fw_work -> module );
1156- kfree_const (fw_work -> name );
1157- kfree (fw_work );
1166+ spin_lock_irq (& firmware_work_lock );
1167+ if (!list_empty (& fw_work -> list )) {
1168+ list_del_init (& fw_work -> list );
1169+ spin_unlock_irq (& firmware_work_lock );
1170+ firmware_work_free (fw_work );
1171+ return ;
1172+ }
1173+ spin_unlock_irq (& firmware_work_lock );
11581174}
11591175
11601176
@@ -1164,6 +1180,7 @@ static int _request_firmware_nowait(
11641180 void (* cont )(const struct firmware * fw , void * context ), bool nowarn )
11651181{
11661182 struct firmware_work * fw_work ;
1183+ unsigned long flags ;
11671184
11681185 fw_work = kzalloc_obj (struct firmware_work , gfp );
11691186 if (!fw_work )
@@ -1196,7 +1213,12 @@ static int _request_firmware_nowait(
11961213
11971214 get_device (fw_work -> device );
11981215 INIT_WORK (& fw_work -> work , request_firmware_work_func );
1216+
1217+ spin_lock_irqsave (& firmware_work_lock , flags );
1218+ list_add_tail (& fw_work -> list , & firmware_work_list );
11991219 schedule_work (& fw_work -> work );
1220+ spin_unlock_irqrestore (& firmware_work_lock , flags );
1221+
12001222 return 0 ;
12011223}
12021224
@@ -1259,6 +1281,44 @@ int firmware_request_nowait_nowarn(
12591281}
12601282EXPORT_SYMBOL_GPL (firmware_request_nowait_nowarn );
12611283
1284+ /**
1285+ * request_firmware_nowait_cancel() - cancel an async firmware request
1286+ * @device: device for which the firmware is being loaded
1287+ * @context: context passed to request_firmware_nowait()
1288+ * @cont: callback passed to request_firmware_nowait()
1289+ *
1290+ * Cancel a pending request_firmware_nowait() request for @device, @context
1291+ * and @cont. If the associated work has already started, this function waits
1292+ * until the callback has returned. If the callback has already completed, this
1293+ * function does nothing.
1294+ *
1295+ * This function may sleep.
1296+ */
1297+ void request_firmware_nowait_cancel (struct device * device , void * context ,
1298+ void (* cont )(const struct firmware * fw ,
1299+ void * context ))
1300+ {
1301+ struct firmware_work * fw_work = NULL ;
1302+ struct firmware_work * tmp ;
1303+
1304+ spin_lock_irq (& firmware_work_lock );
1305+ list_for_each_entry_reverse (tmp , & firmware_work_list , list ) {
1306+ if (tmp -> device == device && tmp -> context == context &&
1307+ tmp -> cont == cont ) {
1308+ fw_work = tmp ;
1309+ list_del_init (& fw_work -> list );
1310+ break ;
1311+ }
1312+ }
1313+ spin_unlock_irq (& firmware_work_lock );
1314+
1315+ if (!fw_work )
1316+ return ;
1317+ cancel_work_sync (& fw_work -> work );
1318+ firmware_work_free (fw_work );
1319+ }
1320+ EXPORT_SYMBOL_GPL (request_firmware_nowait_cancel );
1321+
12621322#ifdef CONFIG_FW_CACHE
12631323static ASYNC_DOMAIN_EXCLUSIVE (fw_cache_domain );
12641324
0 commit comments