Commit 025742cc authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

greybus: Merge branch 'master' into vibrator-gb

parents 396671b1 374e6a26
greybus-y := core.o \
gbuf.o \
sysfs.o \
debugfs.o \
ap.o \
......
......@@ -29,6 +29,21 @@ struct gb_connection *gb_hd_connection_find(struct greybus_host_device *hd,
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
......
......@@ -53,6 +53,8 @@ void gb_connection_exit(struct gb_connection *connection);
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, ...);
......
......@@ -226,12 +226,6 @@ static int __init gb_init(void)
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 @@ static int __init gb_init(void)
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 @@ static void __exit gb_exit(void)
{
gb_protocol_exit();
gb_operation_exit();
gb_gbuf_exit();
gb_ap_exit();
bus_unregister(&greybus_bus_type);
gb_debugfs_cleanup();
......
......@@ -99,6 +99,9 @@ static int alloc_gbuf_data(struct gbuf *gbuf, unsigned int size,
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 @@ static void free_gbuf_data(struct gbuf *gbuf)
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 @@ static int submit_gbuf(struct gbuf *gbuf, gfp_t gfp_mask)
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 */
......
/*
* 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;
}
......@@ -153,7 +153,7 @@ static int gb_gpio_proto_version_operation(struct gb_gpio_controller *gb_gpio_co
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 @@ static int gb_gpio_line_count_operation(struct gb_gpio_controller *gb_gpio_contr
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 @@ static int gb_gpio_activate_operation(struct gb_gpio_controller *gb_gpio_control
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 @@ static int gb_gpio_activate_operation(struct gb_gpio_controller *gb_gpio_control
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 @@ static int gb_gpio_deactivate_operation(struct gb_gpio_controller *gb_gpio_contr
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 @@ static int gb_gpio_deactivate_operation(struct gb_gpio_controller *gb_gpio_contr
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 @@ static int gb_gpio_get_direction_operation(struct gb_gpio_controller *gb_gpio_co
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 @@ static int gb_gpio_get_direction_operation(struct gb_gpio_controller *gb_gpio_co
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 @@ static int gb_gpio_direction_in_operation(struct gb_gpio_controller *gb_gpio_con
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 @@ static int gb_gpio_direction_in_operation(struct gb_gpio_controller *gb_gpio_con
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 @@ static int gb_gpio_direction_out_operation(struct gb_gpio_controller *gb_gpio_co
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 @@ static int gb_gpio_direction_out_operation(struct gb_gpio_controller *gb_gpio_co
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 @@ static int gb_gpio_get_value_operation(struct gb_gpio_controller *gb_gpio_contro
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 @@ static int gb_gpio_get_value_operation(struct gb_gpio_controller *gb_gpio_contro
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 @@ static int gb_gpio_set_value_operation(struct gb_gpio_controller *gb_gpio_contro
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 @@ static int gb_gpio_set_value_operation(struct gb_gpio_controller *gb_gpio_contro
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 @@ static int gb_gpio_set_debounce_operation(struct gb_gpio_controller *gb_gpio_con
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 @@ static int gb_gpio_set_debounce_operation(struct gb_gpio_controller *gb_gpio_con
goto out;
}
response = operation->response_payload;
response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "set debounce response %hhu",
response->status);
......
......@@ -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 gbuf {
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 {
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;
......
......@@ -118,7 +118,7 @@ static int gb_i2c_proto_version_operation(struct gb_i2c_device *gb_i2c_dev)
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 @@ static int gb_i2c_functionality_operation(struct gb_i2c_device *gb_i2c_dev)
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 @@ static int gb_i2c_timeout_operation(struct gb_i2c_device *gb_i2c_dev, u16 msec)
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 @@ static int gb_i2c_timeout_operation(struct gb_i2c_device *gb_i2c_dev, u16 msec)
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 @@ static int gb_i2c_retries_operation(struct gb_i2c_device *gb_i2c_dev,
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 @@ static int gb_i2c_retries_operation(struct gb_i2c_device *gb_i2c_dev,
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 @@ gb_i2c_transfer_request(struct gb_connection *connection,
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 @@ static int gb_i2c_transfer_operation(struct gb_i2c_device *gb_i2c_dev,
goto out;
}
response = operation->response_payload;
response = operation->response.payload;
if (response->status) {
if (response->status == GB_OP_RETRY) {
ret = -EAGAIN;
......
......@@ -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 @@ static void gb_pending_operation_insert(struct gb_operation *operation)
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 @@ gb_pending_operation_find(struct gb_connection *connection, u16 id)
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 @@ int gb_operation_wait(struct gb_operation *operation)
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 @@ static void gb_operation_request_handle(struct gb_operation *operation)
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 @@ static void gb_operation_recv_work(struct work_struct *recv_work)
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 @@ static void operation_timeout(struct work_struct *work)
* initialize it here (it'll be overwritten by the incoming
* message).
*/
static struct gbuf *gb_operation_gbuf_create(struct gb_operation *operation,
static int gb_operation_message_init(struct gb_operation *operation,
u8 type, size_t size,
bool data_out)
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 @@ static struct gbuf *gb_operation_gbuf_create(struct gb_operation *operation,
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 *gb_operation_create(struct gb_connection *connection,
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 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection,
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 @@ static void _gb_operation_destroy(struct kref *kref)
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 @@ int gb_operation_request_send(struct gb_operation *operation,
*/
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 @@ void gb_connection_operation_recv(struct gb_connection *connection,
}
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 @@ void gb_connection_operation_recv(struct gb_connection *connection,
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_connection_operation_recv(struct gb_connection *connection,
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)
......
......@@ -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 @@ enum gb_operation_status {
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 @@ enum gb_operation_status {
* 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 gb_operation {
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,
......
......@@ -110,7 +110,7 @@ static int gb_pwm_proto_version_operation(struct gb_pwm_chip *pwmc)
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 @@ static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc)
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 @@ static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
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 @@ static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
goto out;
}
response = operation->response_payload;
response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "disable response %hhu",
response->status);
......
......@@ -229,7 +229,7 @@ static int send_data(struct gb_tty *tty, u16 size, const u8 *data)
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 @@ static int send_data(struct gb_tty *tty, u16 size, const u8 *data)
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 @@ static int send_line_coding(struct gb_tty *tty,
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 @@ static int send_line_coding(struct gb_tty *tty,
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 @@ static int send_control(struct gb_tty *tty, u16 control)
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 @@ static int send_control(struct gb_tty *tty, u16 control)
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 @@ static int send_break(struct gb_tty *tty, u8 state)
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 @@ static int send_break(struct gb_tty *tty, u8 state)
goto out;
}
response = operation->response_payload;
response = operation->response.payload;
if (response->status) {
gb_connection_err(connection, "send break response %hhu",
response->status);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment