Skip to contentSkip to conversation

request_firmware() private workqueue (was: Re: Using firmware_class with recent 2.6 kernels)

PATCH In review Manuel Estrada Sainz 2 participants 4 messages Jul 26, 2003 – Aug 1, 2003 1 message not in the archive

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

PATCH 1/1 request_firmware() private workqueue (was: Re: Using firmware_class with recent 2.6 kernels)

On Mon, Jul 21, 2003 at 01:41:11PM +0200, Michael Hunold wrote:
[snip]

Quoted 9 lines

To get a start, I took your sample driver and compiled it as a module. I commented out all firmware load methods, except the async notification I'm most interested in.

When I load the module, it prints the debug message and goes to sleep -- ok. But now the system is completely frozen (no keyboard or mouse interaction possible) until the timeout is reached and the async notification function is called, which of course says that the firmware could not been loaded.

Using a private workqueue fixes the issue, sleeping for many seconds from the common workqueue was not nice.

Note that the problem only happens when appropriate firmware hotplug support is not available and request_firmware_work_func() has to wait until the timeout.

About the attached patch:

- use a private workqueue so we can sleep without interfering with other subsystems.

Have a nice day

Manuel

Signature · 6 lines
--- Manuel Estrada Sainz <[email protected]>
                         <[email protected]>
			 <[email protected]>
------------------------ <[email protected]> -------------------
Let us have the serenity to accept the things we cannot change, courage to
change the things we can, and wisdom to know the difference.
#2 lore raw
Quoted 1 line · Manuel Estrada Sainz

On Mon, Jul 21, 2003 at 01:41:11PM +0200, Michael Hunold wrote:

[snip]

Quoted 4 lines

About the attached patch:

- use a private workqueue so we can sleep without interfering with other subsystems.

Oops, as usuall I forgot to attach the patch, It is attached now.

Sorry

Manuel

Signature · 6 lines
--- Manuel Estrada Sainz <[email protected]>
                         <[email protected]>
			 <[email protected]>
------------------------ <[email protected]> -------------------
Let us have the serenity to accept the things we cannot change, courage to
change the things we can, and wisdom to know the difference.

Index: firmware_class.c
===================================================================
RCS file: /home/cvs/linux-2.5/drivers/base/firmware_class.c,v retrieving revision 1.3

firmware_class.c +11 -1
diff -u -r1.3 firmware_class.c
@@ -22,6 +22,8 @@
 MODULE_LICENSE("GPL");
 
 static int loading_timeout = 10;	/* In seconds */
+static struct workqueue_struct *firmware_wq;
+
 
 struct firmware_priv {
 	char fw_id[FIRMWARE_NAME_MAX];
@@ -467,7 +469,7 @@
 	};
 	INIT_WORK(&fw_work->work, request_firmware_work_func, fw_work);
 
-	schedule_work(&fw_work->work);
+	queue_work(firmware_wq, &fw_work->work);
 	return 0;
 }
 
@@ -485,12 +487,20 @@
 		       __FUNCTION__);
 		class_unregister(&firmware_class);
 	}
+	firmware_wq = create_workqueue("firmware");
+	if (!firmware_wq) {
+		printk(KERN_ERR "%s: create_workqueue failed\n", __FUNCTION__);
+		class_remove_file(&firmware_class, &class_attr_timeout);
+		class_unregister(&firmware_class);
+		error = -EIO;
+	}
 	return error;
 
 }
 static void __exit
 firmware_class_exit(void)
 {
+	destroy_workqueue(firmware_wq);
 	class_remove_file(&firmware_class, &class_attr_timeout);
 	class_unregister(&firmware_class);
 }
#3 lore raw

Re: [PATCH] request_firmware() private workqueue

Hello Manuel,

I've applied your patches
- request_firmware_own-workqueue.diff
- sysfs-bin-unbreak.diff

and it's working very well for the av7110 DVB driver.

I hope that these patches are applied to the mainline kernel soon, so the other DVB drivers which need binary firmware blobs (namely dvb-ttusb-dec, dvb-ttusb-budget and one frontend driver) can be ported.

This will get rid of the av7110 firmware in the kernel and the ugly config hacks to get the other drivers working.

CU
Michael.

#4 lore raw

[PATCH] Re: request_firmware() private workqueue

Quoted 6 lines · Michael Hunold

Hello Manuel,

I've applied your patches
- request_firmware_own-workqueue.diff
- sysfs-bin-unbreak.diff

Quoted 8 lines

and it's working very well for the av7110 DVB driver.

I hope that these patches are applied to the mainline kernel soon, so the other DVB drivers which need binary firmware blobs (namely dvb-ttusb-dec, dvb-ttusb-budget and one frontend driver) can be ported.

This will get rid of the av7110 firmware in the kernel and the ugly config hacks to get the other drivers working.

In it's current form request_firmware_async() sleeps way too long on the system's shared workqueue, which make it unresponsive until the firmware load finishes or gets canceled.

The attached patch makes it use it's own workqueue, please apply.

Have a nice day

Manuel

PS: the sysfs issue is handled in a separate email.

Signature · 6 lines
--- Manuel Estrada Sainz <[email protected]>
                         <[email protected]>
			 <[email protected]>
------------------------ <[email protected]> -------------------
Let us have the serenity to accept the things we cannot change, courage to
change the things we can, and wisdom to know the difference.

Index: drivers/base/firmware_class.c
===================================================================
RCS file: /home/cvs/linux-2.5/drivers/base/firmware_class.c,v retrieving revision 1.3

base/firmware_class.c +11 -1
diff -u -r1.3 drivers/base/firmware_class.c
@@ -22,6 +22,8 @@
 MODULE_LICENSE("GPL");
 
 static int loading_timeout = 10;	/* In seconds */
+static struct workqueue_struct *firmware_wq;
+
 
 struct firmware_priv {
 	char fw_id[FIRMWARE_NAME_MAX];
@@ -467,7 +469,7 @@
 	};
 	INIT_WORK(&fw_work->work, request_firmware_work_func, fw_work);
 
-	schedule_work(&fw_work->work);
+	queue_work(firmware_wq, &fw_work->work);
 	return 0;
 }
 
@@ -485,12 +487,20 @@
 		       __FUNCTION__);
 		class_unregister(&firmware_class);
 	}
+	firmware_wq = create_workqueue("firmware");
+	if (!firmware_wq) {
+		printk(KERN_ERR "%s: create_workqueue failed\n", __FUNCTION__);
+		class_remove_file(&firmware_class, &class_attr_timeout);
+		class_unregister(&firmware_class);
+		error = -EIO;
+	}
 	return error;
 
 }
 static void __exit
 firmware_class_exit(void)
 {
+	destroy_workqueue(firmware_wq);
 	class_remove_file(&firmware_class, &class_attr_timeout);
 	class_unregister(&firmware_class);
 }