Re: [PATCH v5 2/5] firmware: encapsulate firmware loading status

From: Daniel Wagner
Date: Tue Sep 13 2016 - 05:47:19 EST


Hi Luis,


On 09/09/2016 02:12 PM, Daniel Wagner wrote:
The firmware user helper code tracks the current state of the loading
process via unsigned long status and a complection in struct
firmware_buf. We only need this for the usermode helper as such we can
encapsulate all this data into its own data structure.

I don't think we are able to move the completion code into a CONFIG_FW_LOADER_HELPER section. The direct loading path uses completion as well.

+#ifdef CONFIG_FW_LOADER_USER_HELPER
+
+enum {
+ FW_UMH_UNKNOWN,
+ FW_UMH_LOADING,
+ FW_UMH_DONE,
+ FW_UMH_ABORTED,
+};

The direct loading path just uses two states, LOADING and DONE. ABORTED is not used.

+struct fw_umh {
+ struct completion completion;
+ unsigned long status;
+};
+
+static void fw_umh_init(struct fw_umh *fw_umh)
+{
+ init_completion(&fw_umh->completion);
+ fw_umh->status = FW_UMH_UNKNOWN;
+}
+
+static int __fw_umh_check(struct fw_umh *fw_umh, unsigned long status)
+{
+ return test_bit(status, &fw_umh->status);
+}
+
+static int fw_umh_wait_timeout(struct fw_umh *fw_umh, long timeout)
+{
+ int ret;
+
+ ret = wait_for_completion_interruptible_timeout(&fw_umh->completion,
+ timeout);
+ if (ret != 0 && test_bit(FW_UMH_ABORTED, &fw_umh->status))
+ return -ENOENT;
+
+ return ret;
+}
+
+static void __fw_umh_set(struct fw_umh *fw_umh,
+ unsigned long status)
+{
+ set_bit(status, &fw_umh->status);
+
+ if (status == FW_UMH_DONE || status == FW_UMH_ABORTED) {
+ clear_bit(FW_UMH_LOADING, &fw_umh->status);
+ complete_all(&fw_umh->completion);
+ }
+}
+
+#define fw_umh_start(fw_umh) \
+ __fw_umh_set(fw_umh, FW_UMH_LOADING)
+#define fw_umh_done(fw_umh) \
+ __fw_umh_set(fw_umh, FW_UMH_DONE)
+#define fw_umh_aborted(fw_umh) \
+ __fw_umh_set(fw_umh, FW_UMH_ABORTED)
+#define fw_umh_is_loading(fw_umh) \
+ __fw_umh_check(fw_umh, FW_UMH_LOADING)
+#define fw_umh_is_done(fw_umh) \
+ __fw_umh_check(fw_umh, FW_UMH_DONE)
+#define fw_umh_is_aborted(fw_umh) \
+ __fw_umh_check(fw_umh, FW_UMH_ABORTED)
+
+#else /* CONFIG_FW_LOADER_USER_HELPER */
+
+#define fw_umh_wait_timeout(fw_st, long) 0
+
+#define fw_umh_done(fw_st)
+#define fw_umh_is_done(fw_st) true
+#define fw_umh_is_aborted(fw_st) false

We still need the implementation for fw_umh_wait_timeout() and fw_umh_start(), fw_umh_done() etc. fw_umh_is_aborted() is not needed.


@@ -309,8 +373,7 @@ static void fw_finish_direct_load(struct device *device,
struct firmware_buf *buf)
{
mutex_lock(&fw_lock);
- set_bit(FW_STATUS_DONE, &buf->status);
- complete_all(&buf->completion);
+ fw_umh_done(&buf->fw_umh);
mutex_unlock(&fw_lock);
}

Here we signal that we have loaded the firmware

/* wait until the shared firmware_buf becomes ready (or error) */
static int sync_cached_firmware_buf(struct firmware_buf *buf)
{
int ret = 0;

mutex_lock(&fw_lock);
- while (!test_bit(FW_STATUS_DONE, &buf->status)) {
- if (is_fw_load_aborted(buf)) {
+ while (!fw_umh_is_done(&buf->fw_umh)) {
+ if (fw_umh_is_aborted(&buf->fw_umh)) {
ret = -ENOENT;
break;
}
mutex_unlock(&fw_lock);
- ret = wait_for_completion_interruptible(&buf->completion);
+ ret = fw_umh_wait_timeout(&buf->fw_umh, 0);
mutex_lock(&fw_lock);
}

and here we here we wait for it.

So I suggest to rename it back to fw_status_ and don't move it inside a CONFIG_FW_LOADER_HELPER section. Drop the special handling of the ABORTED and add instead a comment that the ABORTED state is not used for direct loading. This special handling makes unnecessary more complex. This is a slowpath and this micro optimization is helping to maintain the code.

cheers,
daniel