greybus: Merge branch 'master' into vibrator-gb
diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile
index 198539c..b254516 100644
--- a/drivers/staging/greybus/Makefile
+++ b/drivers/staging/greybus/Makefile
@@ -1,5 +1,4 @@
greybus-y := core.o \
- gbuf.o \
sysfs.o \
debugfs.o \
ap.o \
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
index cb6e2e1..258d96c 100644
--- a/drivers/staging/greybus/connection.c
+++ b/drivers/staging/greybus/connection.c
@@ -29,6 +29,21 @@
return connection;
}
+void greybus_cport_in(struct greybus_host_device *hd, u16 cport_id,
+ u8 *data, size_t length)
+{
+ struct gb_connection *connection;
+
+ connection = gb_hd_connection_find(hd, cport_id);
+ if (!connection) {
+ dev_err(hd->parent,
+ "nonexistent connection (%zu bytes dropped)\n", length);
+ return;
+ }
+ gb_connection_operation_recv(connection, data, length);
+}
+EXPORT_SYMBOL_GPL(greybus_cport_in);
+
/*
* Allocate an available CPort Id for use for the host side of the
* given connection. The lowest-available id is returned, so the
diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h
index 5e96967..bcaad47 100644
--- a/drivers/staging/greybus/connection.h
+++ b/drivers/staging/greybus/connection.h
@@ -53,6 +53,8 @@
struct gb_connection *gb_hd_connection_find(struct greybus_host_device *hd,
u16 cport_id);
+void greybus_cport_in(struct greybus_host_device *hd, u16 cport_id,
+ u8 *data, size_t length);
__printf(2, 3)
void gb_connection_err(struct gb_connection *connection, const char *fmt, ...);
diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c
index 26e4b44..588e624 100644
--- a/drivers/staging/greybus/core.c
+++ b/drivers/staging/greybus/core.c
@@ -226,12 +226,6 @@
goto error_ap;
}
- retval = gb_gbuf_init();
- if (retval) {
- pr_err("gb_gbuf_init failed\n");
- goto error_gbuf;
- }
-
retval = gb_operation_init();
if (retval) {
pr_err("gb_operation_init failed\n");
@@ -250,8 +244,6 @@
error_protocol:
gb_operation_exit();
error_operation:
- gb_gbuf_exit();
-error_gbuf:
gb_ap_exit();
error_ap:
bus_unregister(&greybus_bus_type);
@@ -265,7 +257,6 @@
{
gb_protocol_exit();
gb_operation_exit();
- gb_gbuf_exit();
gb_ap_exit();
bus_unregister(&greybus_bus_type);
gb_debugfs_cleanup();
diff --git a/drivers/staging/greybus/es1-ap-usb.c b/drivers/staging/greybus/es1-ap-usb.c
index e24012a..e276f0c 100644
--- a/drivers/staging/greybus/es1-ap-usb.c
+++ b/drivers/staging/greybus/es1-ap-usb.c
@@ -99,6 +99,9 @@
u32 cport_reserve = gbuf->dest_cport_id == CPORT_ID_BAD ? 0 : 1;
u8 *buffer;
+ if (gbuf->transfer_buffer)
+ return -EALREADY;
+
if (size > ES1_GBUF_MSG_SIZE) {
pr_err("guf was asked to be bigger than %ld!\n",
ES1_GBUF_MSG_SIZE);
@@ -146,6 +149,7 @@
if (gbuf->dest_cport_id != CPORT_ID_BAD)
transfer_buffer--; /* Back up to cport id */
kfree(transfer_buffer);
+ gbuf->transfer_buffer = NULL;
}
#define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */
@@ -214,6 +218,8 @@
struct urb *urb;
transfer_buffer = gbuf->transfer_buffer;
+ if (!transfer_buffer)
+ return -EINVAL;
buffer = &transfer_buffer[-1]; /* yes, we mean -1 */
/* Find a free urb */
diff --git a/drivers/staging/greybus/gbuf.c b/drivers/staging/greybus/gbuf.c
deleted file mode 100644
index 6f8873af..0000000
--- a/drivers/staging/greybus/gbuf.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Greybus gbuf handling
- *
- * Copyright 2014 Google Inc.
- *
- * Released under the GPLv2 only.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/kref.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-
-#include "greybus.h"
-
-static struct kmem_cache *gbuf_head_cache;
-
-/**
- * greybus_alloc_gbuf - allocate a greybus buffer
- *
- * @gmod: greybus device that wants to allocate this
- * @cport: cport to send the data to
- * @complete: callback when the gbuf is finished with
- * @size: size of the buffer
- * @gfp_mask: allocation mask
- *
- * TODO: someday it will be nice to handle DMA, but for now, due to the
- * architecture we are stuck with, the greybus core has to allocate the buffer
- * that the driver can then fill up with the data to be sent out. Curse
- * hardware designers for this issue...
- */
-struct gbuf *greybus_alloc_gbuf(struct greybus_host_device *hd,
- u16 dest_cport_id,
- unsigned int size,
- gfp_t gfp_mask)
-{
- struct gbuf *gbuf;
- int retval;
-
- gbuf = kmem_cache_zalloc(gbuf_head_cache, gfp_mask);
- if (!gbuf)
- return NULL;
-
- kref_init(&gbuf->kref);
- gbuf->hd = hd;
- gbuf->dest_cport_id = dest_cport_id;
- gbuf->status = -EBADR; /* Initial value--means "never set" */
-
- /* Host controller specific allocation for the actual buffer */
- retval = hd->driver->alloc_gbuf_data(gbuf, size, gfp_mask);
- if (retval) {
- kmem_cache_free(gbuf_head_cache, gbuf);
- return NULL;
- }
-
- return gbuf;
-}
-EXPORT_SYMBOL_GPL(greybus_alloc_gbuf);
-
-static DEFINE_MUTEX(gbuf_mutex);
-
-static void free_gbuf(struct kref *kref)
-{
- struct gbuf *gbuf = container_of(kref, struct gbuf, kref);
-
- gbuf->hd->driver->free_gbuf_data(gbuf);
-
- kmem_cache_free(gbuf_head_cache, gbuf);
- mutex_unlock(&gbuf_mutex);
-}
-
-void greybus_free_gbuf(struct gbuf *gbuf)
-{
- /* drop the reference count and get out of here */
- kref_put_mutex(&gbuf->kref, free_gbuf, &gbuf_mutex);
-}
-EXPORT_SYMBOL_GPL(greybus_free_gbuf);
-
-struct gbuf *greybus_get_gbuf(struct gbuf *gbuf)
-{
- mutex_lock(&gbuf_mutex);
- kref_get(&gbuf->kref);
- mutex_unlock(&gbuf_mutex);
- return gbuf;
-}
-EXPORT_SYMBOL_GPL(greybus_get_gbuf);
-
-int greybus_submit_gbuf(struct gbuf *gbuf, gfp_t gfp_mask)
-{
- gbuf->status = -EINPROGRESS;
-
- return gbuf->hd->driver->submit_gbuf(gbuf, gfp_mask);
-}
-
-void greybus_kill_gbuf(struct gbuf *gbuf)
-{
- if (gbuf->status != -EINPROGRESS)
- return;
-
- gbuf->hd->driver->kill_gbuf(gbuf);
-}
-
-void greybus_cport_in(struct greybus_host_device *hd, u16 cport_id,
- u8 *data, size_t length)
-{
- struct gb_connection *connection;
-
- connection = gb_hd_connection_find(hd, cport_id);
- if (!connection) {
- dev_err(hd->parent,
- "nonexistent connection (%zu bytes dropped)\n", length);
- return;
- }
- gb_connection_operation_recv(connection, data, length);
-}
-EXPORT_SYMBOL_GPL(greybus_cport_in);
-
-int gb_gbuf_init(void)
-{
- gbuf_head_cache = kmem_cache_create("gbuf_head_cache",
- sizeof(struct gbuf), 0, 0, NULL);
- return 0;
-}
-
-void gb_gbuf_exit(void)
-{
- kmem_cache_destroy(gbuf_head_cache);
- gbuf_head_cache = NULL;
-}
diff --git a/drivers/staging/greybus/gpio-gb.c b/drivers/staging/greybus/gpio-gb.c
index 473df4d4..6f4609d 100644
--- a/drivers/staging/greybus/gpio-gb.c
+++ b/drivers/staging/greybus/gpio-gb.c
@@ -153,7 +153,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "version response %hhu",
response->status);
@@ -199,7 +199,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "line count response %hhu",
response->status);
@@ -234,7 +234,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
/* Synchronous operation--no callback */
@@ -244,7 +244,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "activate response %hhu",
response->status);
@@ -278,7 +278,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
/* Synchronous operation--no callback */
@@ -288,7 +288,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "deactivate response %hhu",
response->status);
@@ -320,7 +320,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
/* Synchronous operation--no callback */
@@ -330,7 +330,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "get direction response %hhu",
response->status);
@@ -369,7 +369,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
/* Synchronous operation--no callback */
@@ -379,7 +379,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "direction in response %hhu",
response->status);
@@ -412,7 +412,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
request->value = value_high ? 1 : 0;
@@ -423,7 +423,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "direction out response %hhu",
response->status);
@@ -456,7 +456,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
/* Synchronous operation--no callback */
@@ -466,7 +466,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "get value response %hhu",
response->status);
@@ -507,7 +507,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
request->value = value_high ? 1 : 0;
@@ -518,7 +518,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "set value response %hhu",
response->status);
@@ -554,7 +554,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
request->usec = cpu_to_le16(debounce_usec);
@@ -565,7 +565,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "set debounce response %hhu",
response->status);
diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h
index 90469bb..301bd45 100644
--- a/drivers/staging/greybus/greybus.h
+++ b/drivers/staging/greybus/greybus.h
@@ -56,82 +56,6 @@
#define HOST_DEV_CPORT_ID_MAX CONFIG_HOST_DEV_CPORT_ID_MAX
#define CPORT_ID_BAD U16_MAX /* UniPro max id is 4095 */
-/*
- gbuf
-
- This is the "main" data structure to send / receive Greybus messages
-
- There are two different "views" of a gbuf structure:
- - a greybus driver
- - a greybus host controller
-
- A Greybus driver needs to worry about the following:
- - creating a gbuf
- - putting data into a gbuf
- - sending a gbuf to a device
- - receiving a gbuf from a device
-
- Creating a gbuf:
- A greybus driver calls greybus_alloc_gbuf()
- Putting data into a gbuf:
- copy data into gbuf->transfer_buffer
- Send a gbuf:
- A greybus driver calls greybus_submit_gbuf()
- The completion function in a gbuf will be called if the gbuf is successful
- or not. That completion function runs in user context. After the
- completion function is called, the gbuf must not be touched again as the
- greybus core "owns" it. But, if a greybus driver wants to "hold on" to a
- gbuf after the completion function has been called, a reference must be
- grabbed on the gbuf with a call to greybus_get_gbuf(). When finished with
- the gbuf, call greybus_free_gbuf() and when the last reference count is
- dropped, it will be removed from the system.
- Receive a gbuf:
- A greybus driver calls gb_register_cport_complete() with a pointer to the
- callback function to be called for when a gbuf is received from a specific
- cport and device. That callback will be made in user context with a gbuf
- when it is received. To stop receiving messages, call
- gb_deregister_cport_complete() for a specific cport.
-
-
- Greybus Host controller drivers need to provide
- - a way to allocate the transfer buffer for a gbuf
- - a way to free the transfer buffer for a gbuf when it is "finished"
- - a way to submit gbuf for transmissions
- - notify the core the gbuf is complete
- - receive gbuf from the wire and submit them to the core
- - a way to send and receive svc messages
- Allocate a transfer buffer
- the host controller function alloc_gbuf_data is called
- Free a transfer buffer
- the host controller function free_gbuf_data is called
- Submit a gbuf to the hardware
- the host controller function submit_gbuf is called
- Notify the gbuf is complete
- the host controller driver must call greybus_gbuf_finished()
- Submit a SVC message to the hardware
- the host controller function send_svc_msg is called
- Receive gbuf messages
- the host controller driver must call greybus_cport_in() with the data
- Reveive SVC messages from the hardware
- The host controller driver must call greybus_svc_in
-
-
-*/
-
-struct gbuf {
- struct kref kref;
-
- struct greybus_host_device *hd;
- u16 dest_cport_id; /* Destination CPort id */
- int status;
-
- void *transfer_buffer;
- u32 transfer_buffer_length;
-
- void *hcd_data; /* for the HCD to track the gbuf */
-};
-
-
/* For SP1 hardware, we are going to "hardcode" each device to have all logical
* blocks in order to be able to address them as one unified "unit". Then
* higher up layers will then be able to talk to them as one logical block and
@@ -144,6 +68,7 @@
struct greybus_host_device;
struct svc_msg;
+struct gbuf;
/* Greybus "Host driver" structure, needed by a host controller driver to be
* able to handle both SVC control as well as "real" greybus messages
@@ -177,19 +102,6 @@
struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *hd,
struct device *parent);
void greybus_remove_hd(struct greybus_host_device *hd);
-void greybus_cport_in(struct greybus_host_device *hd, u16 cport_id,
- u8 *data, size_t length);
-
-struct gbuf *greybus_alloc_gbuf(struct greybus_host_device *hd,
- u16 dest_cport_id, unsigned int size,
- gfp_t gfp_mask);
-void greybus_free_gbuf(struct gbuf *gbuf);
-struct gbuf *greybus_get_gbuf(struct gbuf *gbuf);
-#define greybus_put_gbuf greybus_free_gbuf
-
-int greybus_submit_gbuf(struct gbuf *gbuf, gfp_t mem_flags);
-void greybus_kill_gbuf(struct gbuf *gbuf);
-
struct greybus_driver {
const char *name;
diff --git a/drivers/staging/greybus/i2c-gb.c b/drivers/staging/greybus/i2c-gb.c
index c179078..3374173 100644
--- a/drivers/staging/greybus/i2c-gb.c
+++ b/drivers/staging/greybus/i2c-gb.c
@@ -118,7 +118,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "version response %hhu",
response->status);
@@ -170,7 +170,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "functionality response %hhu",
response->status);
@@ -198,7 +198,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->msec = cpu_to_le16(msec);
/* Synchronous operation--no callback */
@@ -208,7 +208,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "timeout response %hhu",
response->status);
@@ -235,7 +235,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->retries = retries;
/* Synchronous operation--no callback */
@@ -245,7 +245,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "retries response %hhu",
response->status);
@@ -321,7 +321,7 @@
if (!operation)
return NULL;
- request = operation->request_payload;
+ request = operation->request.payload;
request->op_count = cpu_to_le16(op_count);
/* Fill in the ops array */
op = &request->ops[0];
@@ -380,7 +380,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
if (response->status == GB_OP_RETRY) {
ret = -EAGAIN;
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index c0161a2..2239883 100644
--- a/drivers/staging/greybus/operation.c
+++ b/drivers/staging/greybus/operation.c
@@ -23,6 +23,7 @@
/*
* XXX This needs to be coordinated with host driver parameters
+ * XXX May need to reduce to allow for message header within a page
*/
#define GB_OPERATION_MESSAGE_SIZE_MAX 4096
@@ -71,7 +72,7 @@
spin_unlock_irq(&gb_operations_lock);
/* Store the operation id in the request header */
- header = operation->request->transfer_buffer;
+ header = operation->request.gbuf.transfer_buffer;
header->id = cpu_to_le16(operation->id);
}
@@ -102,6 +103,20 @@
return found ? operation : NULL;
}
+static int greybus_submit_gbuf(struct gbuf *gbuf, gfp_t gfp_mask)
+{
+ gbuf->status = -EINPROGRESS;
+
+ return gbuf->hd->driver->submit_gbuf(gbuf, gfp_mask);
+}
+
+static void greybus_kill_gbuf(struct gbuf *gbuf)
+{
+ if (gbuf->status != -EINPROGRESS)
+ return;
+
+ gbuf->hd->driver->kill_gbuf(gbuf);
+}
/*
* An operations's response message has arrived. If no callback was
* supplied it was submitted for asynchronous completion, so we notify
@@ -124,7 +139,7 @@
ret = wait_for_completion_interruptible(&operation->completion);
/* If interrupted, cancel the in-flight buffer */
if (ret < 0)
- greybus_kill_gbuf(operation->request);
+ greybus_kill_gbuf(&operation->request.gbuf);
return ret;
}
@@ -134,7 +149,7 @@
struct gb_protocol *protocol = operation->connection->protocol;
struct gb_operation_msg_hdr *header;
- header = operation->request->transfer_buffer;
+ header = operation->request.gbuf.transfer_buffer;
/*
* If the protocol has no incoming request handler, report
@@ -164,7 +179,7 @@
bool incoming_request;
operation = container_of(recv_work, struct gb_operation, recv_work);
- incoming_request = operation->response == NULL;
+ incoming_request = operation->response.gbuf.transfer_buffer == NULL;
if (incoming_request)
gb_operation_request_handle(operation);
gb_operation_complete(operation);
@@ -196,28 +211,42 @@
* initialize it here (it'll be overwritten by the incoming
* message).
*/
-static struct gbuf *gb_operation_gbuf_create(struct gb_operation *operation,
- u8 type, size_t size,
- bool data_out)
+static int gb_operation_message_init(struct gb_operation *operation,
+ u8 type, size_t size,
+ bool request, bool data_out)
{
struct gb_connection *connection = operation->connection;
+ struct greybus_host_device *hd = connection->hd;
+ struct gb_message *message;
struct gb_operation_msg_hdr *header;
struct gbuf *gbuf;
gfp_t gfp_flags = data_out ? GFP_KERNEL : GFP_ATOMIC;
u16 dest_cport_id;
+ int ret;
if (size > GB_OPERATION_MESSAGE_SIZE_MAX)
- return NULL; /* Message too big */
+ return -E2BIG;
+ size += sizeof(*header);
+
+ if (request) {
+ message = &operation->request;
+ } else {
+ message = &operation->response;
+ type |= GB_OPERATION_TYPE_RESPONSE;
+ }
+ gbuf = &message->gbuf;
if (data_out)
dest_cport_id = connection->interface_cport_id;
else
dest_cport_id = CPORT_ID_BAD;
- size += sizeof(*header);
- gbuf = greybus_alloc_gbuf(connection->hd, dest_cport_id,
- size, gfp_flags);
- if (!gbuf)
- return NULL;
+
+ gbuf->hd = hd;
+ gbuf->dest_cport_id = dest_cport_id;
+ gbuf->status = -EBADR; /* Initial value--means "never set" */
+ ret = hd->driver->alloc_gbuf_data(gbuf, size, gfp_flags);
+ if (ret)
+ return ret;
/* Fill in the header structure */
header = (struct gb_operation_msg_hdr *)gbuf->transfer_buffer;
@@ -225,7 +254,17 @@
header->id = 0; /* Filled in when submitted */
header->type = type;
- return gbuf;
+ message->payload = header + 1;
+ message->operation = operation;
+
+ return 0;
+}
+
+static void gb_operation_message_exit(struct gb_message *message)
+{
+ message->operation = NULL;
+ message->payload = NULL;
+ message->gbuf.hd->driver->free_gbuf_data(&message->gbuf);
}
/*
@@ -251,30 +290,23 @@
struct gb_operation *operation;
gfp_t gfp_flags = response_size ? GFP_KERNEL : GFP_ATOMIC;
bool outgoing = response_size != 0;
+ int ret;
operation = kmem_cache_zalloc(gb_operation_cache, gfp_flags);
if (!operation)
return NULL;
operation->connection = connection;
- operation->request = gb_operation_gbuf_create(operation, type,
- request_size,
- outgoing);
- if (!operation->request)
+ ret = gb_operation_message_init(operation, type, request_size,
+ true, outgoing);
+ if (ret)
goto err_cache;
- operation->request_payload = operation->request->transfer_buffer +
- sizeof(struct gb_operation_msg_hdr);
if (outgoing) {
- type |= GB_OPERATION_TYPE_RESPONSE;
- operation->response = gb_operation_gbuf_create(operation,
- type, response_size,
- false);
- if (!operation->response)
+ ret = gb_operation_message_init(operation, type, response_size,
+ false, false);
+ if (ret)
goto err_request;
- operation->response_payload =
- operation->response->transfer_buffer +
- sizeof(struct gb_operation_msg_hdr);
}
INIT_WORK(&operation->recv_work, gb_operation_recv_work);
@@ -290,7 +322,7 @@
return operation;
err_request:
- greybus_free_gbuf(operation->request);
+ gb_operation_message_exit(&operation->request);
err_cache:
kmem_cache_free(gb_operation_cache, operation);
@@ -311,8 +343,8 @@
list_del(&operation->links);
spin_unlock_irq(&gb_operations_lock);
- greybus_free_gbuf(operation->response);
- greybus_free_gbuf(operation->request);
+ gb_operation_message_exit(&operation->response);
+ gb_operation_message_exit(&operation->request);
kmem_cache_free(gb_operation_cache, operation);
}
@@ -349,7 +381,7 @@
*/
operation->callback = callback;
gb_pending_operation_insert(operation);
- ret = greybus_submit_gbuf(operation->request, GFP_KERNEL);
+ ret = greybus_submit_gbuf(&operation->request.gbuf, GFP_KERNEL);
if (ret)
return ret;
@@ -414,7 +446,7 @@
}
cancel_delayed_work(&operation->timeout_work);
gb_pending_operation_remove(operation);
- gbuf = operation->response;
+ gbuf = &operation->response.gbuf;
if (size > gbuf->transfer_buffer_length) {
operation->result = GB_OP_OVERFLOW;
gb_connection_err(connection, "recv buffer too small");
@@ -429,7 +461,7 @@
gb_connection_err(connection, "can't create operation");
return;
}
- gbuf = operation->request;
+ gbuf = &operation->request.gbuf;
}
memcpy(gbuf->transfer_buffer, data, msg_size);
@@ -444,9 +476,9 @@
void gb_operation_cancel(struct gb_operation *operation)
{
operation->canceled = true;
- greybus_kill_gbuf(operation->request);
- if (operation->response)
- greybus_kill_gbuf(operation->response);
+ greybus_kill_gbuf(&operation->request.gbuf);
+ if (operation->response.gbuf.transfer_buffer)
+ greybus_kill_gbuf(&operation->response.gbuf);
}
int gb_operation_init(void)
diff --git a/drivers/staging/greybus/operation.h b/drivers/staging/greybus/operation.h
index dc15c2f..f43531d 100644
--- a/drivers/staging/greybus/operation.h
+++ b/drivers/staging/greybus/operation.h
@@ -11,6 +11,8 @@
#include <linux/completion.h>
+struct gb_operation;
+
enum gb_operation_status {
GB_OP_SUCCESS = 0,
GB_OP_INVALID = 1,
@@ -22,6 +24,23 @@
GB_OP_TIMEOUT = 0xff,
};
+struct gbuf {
+ struct greybus_host_device *hd;
+ u16 dest_cport_id; /* Destination CPort id */
+ int status;
+
+ void *transfer_buffer;
+ u32 transfer_buffer_length;
+
+ void *hcd_data; /* for the HCD to track the gbuf */
+};
+
+struct gb_message {
+ void *payload;
+ struct gb_operation *operation;
+ struct gbuf gbuf;
+};
+
/*
* A Greybus operation is a remote procedure call performed over a
* connection between the AP and a function on Greybus module.
@@ -50,12 +69,11 @@
* is guaranteed to be 64-bit aligned.
* XXX and callback?
*/
-struct gb_operation;
typedef void (*gb_operation_callback)(struct gb_operation *);
struct gb_operation {
struct gb_connection *connection;
- struct gbuf *request;
- struct gbuf *response;
+ struct gb_message request;
+ struct gb_message response;
u16 id;
bool canceled;
@@ -67,10 +85,6 @@
struct kref kref;
struct list_head links; /* connection->{operations,pending} */
-
- /* These are what's used by caller */
- void *request_payload;
- void *response_payload;
};
void gb_connection_operation_recv(struct gb_connection *connection,
diff --git a/drivers/staging/greybus/pwm-gb.c b/drivers/staging/greybus/pwm-gb.c
index 44a4f64..0f46552 100644
--- a/drivers/staging/greybus/pwm-gb.c
+++ b/drivers/staging/greybus/pwm-gb.c
@@ -110,7 +110,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "version response %hhu",
response->status);
@@ -151,7 +151,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "pwm count response %hhu",
response->status);
@@ -181,7 +181,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
/* Synchronous operation--no callback */
@@ -191,7 +191,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "activate response %hhu",
response->status);
@@ -220,7 +220,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
/* Synchronous operation--no callback */
@@ -230,7 +230,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "deactivate response %hhu",
response->status);
@@ -258,7 +258,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
request->duty = duty;
request->period = period;
@@ -270,7 +270,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "config response %hhu",
response->status);
@@ -299,7 +299,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
request->polarity = polarity;
@@ -310,7 +310,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "set polarity response %hhu",
response->status);
@@ -339,7 +339,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
/* Synchronous operation--no callback */
@@ -349,7 +349,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "enable response %hhu",
response->status);
@@ -378,7 +378,7 @@
sizeof(*request), sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->which = which;
/* Synchronous operation--no callback */
@@ -388,7 +388,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "disable response %hhu",
response->status);
diff --git a/drivers/staging/greybus/uart-gb.c b/drivers/staging/greybus/uart-gb.c
index a4f745a..a8c342e 100644
--- a/drivers/staging/greybus/uart-gb.c
+++ b/drivers/staging/greybus/uart-gb.c
@@ -229,7 +229,7 @@
sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->size = cpu_to_le16(size);
memcpy(&request->data[0], data, size);
@@ -241,7 +241,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "send data response %hhu",
response->status);
@@ -267,7 +267,7 @@
sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
memcpy(&request->line_coding, line_coding, sizeof(*line_coding));
/* Synchronous operation--no callback */
@@ -278,7 +278,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "send line coding response %hhu",
response->status);
@@ -304,7 +304,7 @@
sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->control = cpu_to_le16(control);
/* Synchronous operation--no callback */
@@ -315,7 +315,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "send control response %hhu",
response->status);
@@ -345,7 +345,7 @@
sizeof(*response));
if (!operation)
return -ENOMEM;
- request = operation->request_payload;
+ request = operation->request.payload;
request->state = state;
/* Synchronous operation--no callback */
@@ -356,7 +356,7 @@
goto out;
}
- response = operation->response_payload;
+ response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "send break response %hhu",
response->status);