Эх сурвалжийг харах

greybus: greybus-driver: Add intf_oops operation

Add intf_oops operation to SVC Protocol. This
operation will notify the AP about a fatal error
in a module. The request has two arguments:
    -u8 intf - the interface in question
    -u8 reason - reason of the error
The response has no payload.
Upon receiving the Request, the driver disables
the Interface.

Signed-off-by: Georgi Dobrev <gdobrev@mm-sol.com>
Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Ashwin Chaugule <ashwinch@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Georgi Dobrev 9 жил өмнө
parent
commit
57fa2de1e5

+ 7 - 0
drivers/staging/greybus/greybus_protocols.h

@@ -1018,6 +1018,7 @@ struct gb_spi_transfer_response {
 #define GB_SVC_TYPE_INTF_ACTIVATE		0x27
 #define GB_SVC_TYPE_INTF_RESUME			0x28
 #define GB_SVC_TYPE_INTF_MAILBOX_EVENT		0x29
+#define GB_SVC_TYPE_INTF_OOPS			0x2a
 
 /* Greybus SVC protocol status values */
 #define GB_SVC_OP_SUCCESS			0x00
@@ -1357,6 +1358,12 @@ struct gb_svc_intf_mailbox_event_request {
 } __packed;
 /* intf_mailbox_event response has no payload */
 
+struct gb_svc_intf_oops_request {
+	__u8	intf_id;
+	__u8	reason;
+} __packed;
+/* intf_oops response has no payload */
+
 
 /* RAW */
 

+ 50 - 0
drivers/staging/greybus/svc.c

@@ -1112,6 +1112,37 @@ static void gb_svc_process_module_removed(struct gb_operation *operation)
 	gb_module_put(module);
 }
 
+static void gb_svc_process_intf_oops(struct gb_operation *operation)
+{
+	struct gb_svc_intf_oops_request *request;
+	struct gb_connection *connection = operation->connection;
+	struct gb_svc *svc = gb_connection_get_data(connection);
+	struct gb_interface *intf;
+	u8 intf_id;
+	u8 reason;
+
+	/* The request message size has already been verified. */
+	request = operation->request->payload;
+	intf_id = request->intf_id;
+	reason = request->reason;
+
+	intf = gb_svc_interface_lookup(svc, intf_id);
+	if (!intf) {
+		dev_warn(&svc->dev, "unexpected interface-oops event %u\n",
+			 intf_id);
+		return;
+	}
+
+	dev_info(&svc->dev, "Deactivating interface %u, interface oops reason = %u\n",
+		 intf_id, reason);
+
+	mutex_lock(&intf->mutex);
+	intf->disconnected = true;
+	gb_interface_disable(intf);
+	gb_interface_deactivate(intf);
+	mutex_unlock(&intf->mutex);
+}
+
 static void gb_svc_process_intf_mailbox_event(struct gb_operation *operation)
 {
 	struct gb_svc_intf_mailbox_event_request *request;
@@ -1165,6 +1196,9 @@ static void gb_svc_process_deferred_request(struct work_struct *work)
 	case GB_SVC_TYPE_INTF_MAILBOX_EVENT:
 		gb_svc_process_intf_mailbox_event(operation);
 		break;
+	case GB_SVC_TYPE_INTF_OOPS:
+		gb_svc_process_intf_oops(operation);
+		break;
 	default:
 		dev_err(&svc->dev, "bad deferred request type: 0x%02x\n", type);
 	}
@@ -1251,6 +1285,20 @@ static int gb_svc_module_removed_recv(struct gb_operation *op)
 	return gb_svc_queue_deferred_request(op);
 }
 
+static int gb_svc_intf_oops_recv(struct gb_operation *op)
+{
+	struct gb_svc *svc = gb_connection_get_data(op->connection);
+	struct gb_svc_intf_oops_request *request;
+
+	if (op->request->payload_size < sizeof(*request)) {
+		dev_warn(&svc->dev, "short intf-oops request received (%zu < %zu)\n",
+			 op->request->payload_size, sizeof(*request));
+		return -EINVAL;
+	}
+
+	return gb_svc_queue_deferred_request(op);
+}
+
 static int gb_svc_intf_mailbox_event_recv(struct gb_operation *op)
 {
 	struct gb_svc *svc = gb_connection_get_data(op->connection);
@@ -1326,6 +1374,8 @@ static int gb_svc_request_handler(struct gb_operation *op)
 		return gb_svc_module_removed_recv(op);
 	case GB_SVC_TYPE_INTF_MAILBOX_EVENT:
 		return gb_svc_intf_mailbox_event_recv(op);
+	case GB_SVC_TYPE_INTF_OOPS:
+		return gb_svc_intf_oops_recv(op);
 	default:
 		dev_warn(&svc->dev, "unsupported request 0x%02x\n", type);
 		return -EINVAL;