greybus: svc: generalise deferred request handling
Clean up and generalise deferred request handling by simply storing a
reference-counted pointer to the operation itself in the work context.
Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c
index d974b36..6428052 100644
--- a/drivers/staging/greybus/svc.c
+++ b/drivers/staging/greybus/svc.c
@@ -16,10 +16,9 @@
#define CPORT_FLAGS_CSV_N BIT(2)
-struct svc_hotplug {
+struct gb_svc_deferred_request {
struct work_struct work;
- struct gb_connection *connection;
- struct gb_svc_intf_hotplug_request data;
+ struct gb_operation *operation;
};
@@ -349,16 +348,10 @@
ida_simple_remove(&svc->device_id_map, device_id);
}
-/*
- * 'struct svc_hotplug' should be freed by svc_process_hotplug() before it
- * returns, irrespective of success or Failure in bringing up the module.
- */
-static void svc_process_hotplug(struct work_struct *work)
+static void gb_svc_process_intf_hotplug(struct gb_operation *operation)
{
- struct svc_hotplug *svc_hotplug = container_of(work, struct svc_hotplug,
- work);
struct gb_svc_intf_hotplug_request *request;
- struct gb_connection *connection = svc_hotplug->connection;
+ struct gb_connection *connection = operation->connection;
struct gb_svc *svc = connection->private;
struct gb_host_device *hd = connection->hd;
struct gb_interface *intf;
@@ -366,7 +359,7 @@
int ret;
/* The request message size has already been verified. */
- request = &svc_hotplug->data;
+ request = operation->request->payload;
intf_id = request->intf_id;
dev_dbg(&svc->dev, "%s - id = %u\n", __func__, intf_id);
@@ -396,7 +389,7 @@
if (!intf) {
dev_err(&svc->dev, "failed to create interface %hhu\n",
intf_id);
- goto free_svc_hotplug;
+ return;
}
ret = gb_svc_read_and_clear_module_boot_status(intf);
@@ -450,7 +443,7 @@
goto destroy_route;
}
- goto free_svc_hotplug;
+ return;
destroy_route:
gb_svc_route_destroy(svc, svc->ap_intf_id, intf_id);
@@ -463,8 +456,48 @@
ida_simple_remove(&svc->device_id_map, device_id);
destroy_interface:
gb_interface_remove(intf);
-free_svc_hotplug:
- kfree(svc_hotplug);
+}
+
+static void gb_svc_process_deferred_request(struct work_struct *work)
+{
+ struct gb_svc_deferred_request *dr;
+ struct gb_operation *operation;
+ struct gb_svc *svc;
+ u8 type;
+
+ dr = container_of(work, struct gb_svc_deferred_request, work);
+ operation = dr->operation;
+ svc = operation->connection->private;
+ type = operation->request->header->type;
+
+ switch (type) {
+ case GB_SVC_TYPE_INTF_HOTPLUG:
+ gb_svc_process_intf_hotplug(operation);
+ break;
+ default:
+ dev_err(&svc->dev, "bad deferred request type: %02x\n", type);
+ }
+
+ gb_operation_put(operation);
+ kfree(dr);
+}
+
+static int gb_svc_queue_deferred_request(struct gb_operation *operation)
+{
+ struct gb_svc_deferred_request *dr;
+
+ dr = kmalloc(sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ gb_operation_get(operation);
+
+ dr->operation = operation;
+ INIT_WORK(&dr->work, gb_svc_process_deferred_request);
+
+ queue_work(system_unbound_wq, &dr->work);
+
+ return 0;
}
/*
@@ -480,7 +513,6 @@
{
struct gb_svc *svc = op->connection->private;
struct gb_svc_intf_hotplug_request *request;
- struct svc_hotplug *svc_hotplug;
if (op->request->payload_size < sizeof(*request)) {
dev_warn(&svc->dev, "short hotplug request received (%zu < %zu)\n",
@@ -492,17 +524,7 @@
dev_dbg(&svc->dev, "%s - id = %u\n", __func__, request->intf_id);
- svc_hotplug = kmalloc(sizeof(*svc_hotplug), GFP_KERNEL);
- if (!svc_hotplug)
- return -ENOMEM;
-
- svc_hotplug->connection = op->connection;
- memcpy(&svc_hotplug->data, request, sizeof(svc_hotplug->data));
-
- INIT_WORK(&svc_hotplug->work, svc_process_hotplug);
- queue_work(system_unbound_wq, &svc_hotplug->work);
-
- return 0;
+ return gb_svc_queue_deferred_request(op);
}
static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op)