greybus: fw-management: Add ioctl to initiate mode-switch
authorViresh Kumar <viresh.kumar@linaro.org>
Sat, 14 May 2016 18:12:22 +0000 (23:42 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Sat, 14 May 2016 22:23:52 +0000 (00:23 +0200)
Once the interface firmware is loaded successfully to a module,
userspace can ask it to mode switch to the newly loaded firmware.

This patch provides a new ioctl to initiate mode switch.

Userspace can initiate a mode switch if it has previously loaded the
interface firmware successfully, otherwise the firmware core rejects it.

Also, once the mode-switch is initiated, disallow any more interactions
from the userspace.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Tested-by: Karthik Ravi Shankar <karthikrs@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/fw-management.c
drivers/staging/greybus/greybus_firmware.h

index 2db5a11..7c2226a 100644 (file)
@@ -34,6 +34,8 @@ struct fw_mgmt {
        unsigned int            timeout_jiffies;
 
        /* Interface Firmware specific fields */
+       bool                    mode_switch_started;
+       bool                    intf_fw_loaded;
        u8                      intf_fw_request_id;
        u8                      intf_fw_status;
        u16                     intf_fw_major;
@@ -123,6 +125,7 @@ static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt,
        }
 
        fw_mgmt->intf_fw_request_id = ret;
+       fw_mgmt->intf_fw_loaded = false;
        request.request_id = ret;
 
        ret = gb_operation_sync(fw_mgmt->connection,
@@ -183,6 +186,8 @@ static int fw_mgmt_interface_fw_loaded_operation(struct gb_operation *op)
                dev_err(fw_mgmt->parent,
                        "failed to validate interface firmware, status:%02x\n",
                        fw_mgmt->intf_fw_status);
+       else
+               fw_mgmt->intf_fw_loaded = true;
 
        complete(&fw_mgmt->completion);
 
@@ -329,6 +334,10 @@ static int fw_mgmt_ioctl(struct fw_mgmt *fw_mgmt, unsigned int cmd,
        unsigned int timeout;
        int ret;
 
+       /* Reject any operations after mode-switch has started */
+       if (fw_mgmt->mode_switch_started)
+               return -EBUSY;
+
        switch (cmd) {
        case FW_MGMT_IOC_GET_INTF_FW:
                ret = fw_mgmt_interface_fw_version_operation(fw_mgmt, &fw_info);
@@ -408,6 +417,17 @@ static int fw_mgmt_ioctl(struct fw_mgmt *fw_mgmt, unsigned int cmd,
                fw_mgmt->timeout_jiffies = msecs_to_jiffies(timeout);
 
                return 0;
+       case FW_MGMT_IOC_MODE_SWITCH:
+               if (!fw_mgmt->intf_fw_loaded) {
+                       dev_err(fw_mgmt->parent,
+                               "Firmware not loaded for mode-switch\n");
+                       return -EPERM;
+               }
+
+               fw_mgmt->mode_switch_started = true;
+
+               /* FIXME: Initiate mode-switch from here */
+               return 0;
        default:
                return -ENOTTY;
        }
index 9c5ad75..4e194f2 100644 (file)
@@ -79,6 +79,7 @@ struct fw_mgmt_ioc_backend_fw_update {
 #define FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE     _IOWR(FW_MGMT_IOCTL_BASE, 2, struct fw_mgmt_ioc_intf_load_and_validate)
 #define FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE     _IOWR(FW_MGMT_IOCTL_BASE, 3, struct fw_mgmt_ioc_backend_fw_update)
 #define FW_MGMT_IOC_SET_TIMEOUT_MS             _IOW(FW_MGMT_IOCTL_BASE, 4, unsigned int)
+#define FW_MGMT_IOC_MODE_SWITCH                        _IO(FW_MGMT_IOCTL_BASE, 5)
 
 #endif /* __GREYBUS_FIRMWARE_USER_H */