Răsfoiți Sursa

greybus: fw-management: Add ioctl to initiate mode-switch

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>
Viresh Kumar 9 ani în urmă
părinte
comite
04f0e6ebd1

+ 20 - 0
drivers/staging/greybus/fw-management.c

@@ -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);
@@ -407,6 +416,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;

+ 1 - 0
drivers/staging/greybus/greybus_firmware.h

@@ -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 */