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>
This commit is contained in:
Johan Hovold 2015-12-02 18:23:29 +01:00 committed by Greg Kroah-Hartman
parent b4ee82ece8
commit 9ae4109e5d

View File

@ -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 @@ static void gb_svc_intf_remove(struct gb_svc *svc, struct gb_interface *intf)
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 @@ static void svc_process_hotplug(struct work_struct *work)
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 @@ static void svc_process_hotplug(struct work_struct *work)
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 @@ static void svc_process_hotplug(struct work_struct *work)
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_put:
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 @@ static int gb_svc_intf_hotplug_recv(struct gb_operation *op)
{
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 @@ static int gb_svc_intf_hotplug_recv(struct gb_operation *op)
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)