Commit c3278f9f authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

greybus: Merge branch 'master' into vibrator-gb

parents 4b992018 de80073a
...@@ -40,7 +40,7 @@ void greybus_cport_in(struct greybus_host_device *hd, u16 cport_id, ...@@ -40,7 +40,7 @@ void greybus_cport_in(struct greybus_host_device *hd, u16 cport_id,
"nonexistent connection (%zu bytes dropped)\n", length); "nonexistent connection (%zu bytes dropped)\n", length);
return; return;
} }
gb_connection_operation_recv(connection, data, length); gb_connection_recv(connection, data, length);
} }
EXPORT_SYMBOL_GPL(greybus_cport_in); EXPORT_SYMBOL_GPL(greybus_cport_in);
......
...@@ -169,11 +169,9 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver ...@@ -169,11 +169,9 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
* Validate that the driver implements all of the callbacks * Validate that the driver implements all of the callbacks
* so that we don't have to every time we make them. * so that we don't have to every time we make them.
*/ */
if ((!driver->alloc_gbuf_data) || if ((!driver->buffer_alloc) || (!driver->buffer_free) ||
(!driver->free_gbuf_data) || (!driver->buffer_send) || (!driver->buffer_cancel) ||
(!driver->submit_svc) || (!driver->submit_svc)) {
(!driver->submit_gbuf) ||
(!driver->kill_gbuf)) {
pr_err("Must implement all greybus_host_driver callbacks!\n"); pr_err("Must implement all greybus_host_driver callbacks!\n");
return NULL; return NULL;
} }
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#define ES1_SVC_MSG_SIZE (sizeof(struct svc_msg) + SZ_64K) #define ES1_SVC_MSG_SIZE (sizeof(struct svc_msg) + SZ_64K)
#define ES1_GBUF_MSG_SIZE PAGE_SIZE #define ES1_GBUF_MSG_SIZE PAGE_SIZE
static const struct usb_device_id id_table[] = { static const struct usb_device_id id_table[] = {
/* Made up numbers for the SVC USB Bridge in ES1 */ /* Made up numbers for the SVC USB Bridge in ES1 */
{ USB_DEVICE(0xffff, 0x0001) }, { USB_DEVICE(0xffff, 0x0001) },
...@@ -86,70 +85,47 @@ static inline struct es1_ap_dev *hd_to_es1(struct greybus_host_device *hd) ...@@ -86,70 +85,47 @@ static inline struct es1_ap_dev *hd_to_es1(struct greybus_host_device *hd)
static void cport_out_callback(struct urb *urb); static void cport_out_callback(struct urb *urb);
/* /*
* Allocate the actual buffer for this gbuf and device and cport * Allocate a buffer to be sent via UniPro.
*
* We are responsible for setting the following fields in a struct gbuf:
* void *hcpriv;
* void *transfer_buffer;
* u32 transfer_buffer_length;
*/ */
static int alloc_gbuf_data(struct gbuf *gbuf, unsigned int size, static void *buffer_alloc(unsigned int size, gfp_t gfp_mask)
gfp_t gfp_mask)
{ {
u32 cport_reserve = gbuf->dest_cport_id == CPORT_ID_BAD ? 0 : 1;
u8 *buffer; u8 *buffer;
if (gbuf->transfer_buffer)
return -EALREADY;
if (size > ES1_GBUF_MSG_SIZE) { if (size > ES1_GBUF_MSG_SIZE) {
pr_err("guf was asked to be bigger than %ld!\n", pr_err("guf was asked to be bigger than %ld!\n",
ES1_GBUF_MSG_SIZE); ES1_GBUF_MSG_SIZE);
} }
/* For ES2 we need to figure out what cport is going to what endpoint, /*
* but for ES1, it's so dirt simple, we don't have a choice... * For ES1 we need to insert a byte at the front of the data
* to indicate the destination CPort id. We only need one
* extra byte, but we allocate four extra bytes to allow the
* buffer returned to be aligned on a four-byte boundary.
* *
* Also, do a "slow" allocation now, if we need speed, use a cache * This is only needed for outbound data, but we handle
* buffers for inbound data the same way for consistency.
* *
* For ES1 outbound buffers need to insert their target * XXX Do we need to indicate the destination device id too?
* CPort Id before the data; set aside an extra byte for
* that purpose in that case.
*/ */
buffer = kzalloc(cport_reserve + size, gfp_mask); buffer = kzalloc(GB_BUFFER_ALIGN + size, gfp_mask);
if (!buffer) if (buffer)
return -ENOMEM; buffer += GB_BUFFER_ALIGN;
/* Insert the cport id for outbound buffers */ return buffer;
if (cport_reserve) {
if (gbuf->dest_cport_id > (u16)U8_MAX) {
pr_err("gbuf->dest_cport_id (%hd) is out of range!\n",
gbuf->dest_cport_id);
kfree(buffer);
return -EINVAL;
}
*buffer++ = gbuf->dest_cport_id;
}
gbuf->transfer_buffer = buffer;
gbuf->transfer_buffer_length = size;
return 0;
} }
/* Free the memory we allocated with a gbuf */ /* Free a previously-allocated buffer */
static void free_gbuf_data(struct gbuf *gbuf) static void buffer_free(void *buffer)
{ {
u8 *transfer_buffer = gbuf->transfer_buffer; u8 *allocated = buffer;
/* Can be called with a NULL transfer_buffer on some error paths */ /* Can be called with a NULL buffer on some error paths */
if (!transfer_buffer) if (!allocated)
return; return;
/* Account for the cport id in outbound buffers */ /* Account for the space set aside for the prepended cport id */
if (gbuf->dest_cport_id != CPORT_ID_BAD) allocated -= GB_BUFFER_ALIGN;
transfer_buffer--; /* Back up to cport id */ kfree(allocated);
kfree(transfer_buffer);
gbuf->transfer_buffer = NULL;
} }
#define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */ #define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */
...@@ -207,53 +183,86 @@ static struct urb *next_free_urb(struct es1_ap_dev *es1, gfp_t gfp_mask) ...@@ -207,53 +183,86 @@ static struct urb *next_free_urb(struct es1_ap_dev *es1, gfp_t gfp_mask)
return urb; return urb;
} }
static int submit_gbuf(struct gbuf *gbuf, gfp_t gfp_mask) /*
* Returns an opaque cookie value if successful, or a pointer coded
* error otherwise. If the caller wishes to cancel the in-flight
* buffer, it must supply the returned cookie to the cancel routine.
*/
static void *buffer_send(struct greybus_host_device *hd, u16 dest_cport_id,
void *buffer, size_t buffer_size, gfp_t gfp_mask)
{ {
struct greybus_host_device *hd = gbuf->hd;
struct es1_ap_dev *es1 = hd_to_es1(hd); struct es1_ap_dev *es1 = hd_to_es1(hd);
struct usb_device *udev = es1->usb_dev; struct usb_device *udev = es1->usb_dev;
u8 *transfer_buffer = buffer;
int transfer_buffer_size;
int retval; int retval;
u8 *transfer_buffer;
u8 *buffer;
struct urb *urb; struct urb *urb;
transfer_buffer = gbuf->transfer_buffer; if (!buffer) {
if (!transfer_buffer) pr_err("null buffer supplied to send\n");
return -EINVAL; return ERR_PTR(-EINVAL);
buffer = &transfer_buffer[-1]; /* yes, we mean -1 */ }
if (buffer_size > (size_t)INT_MAX) {
pr_err("bad buffer size (%zu) supplied to send\n", buffer_size);
return ERR_PTR(-EINVAL);
}
transfer_buffer--;
transfer_buffer_size = buffer_size + 1;
/*
* The data actually transferred will include an indication
* of where the data should be sent. Do one last check of
* the target CPort id before filling it in.
*/
if (dest_cport_id == CPORT_ID_BAD) {
pr_err("request to send inbound data buffer\n");
return ERR_PTR(-EINVAL);
}
if (dest_cport_id > (u16)U8_MAX) {
pr_err("dest_cport_id (%hd) is out of range for ES1\n",
dest_cport_id);
return ERR_PTR(-EINVAL);
}
/* OK, the destination is fine; record it in the transfer buffer */
*transfer_buffer = dest_cport_id;
/* Find a free urb */ /* Find a free urb */
urb = next_free_urb(es1, gfp_mask); urb = next_free_urb(es1, gfp_mask);
if (!urb) if (!urb)
return -ENOMEM; return ERR_PTR(-ENOMEM);
gbuf->hcd_data = urb;
usb_fill_bulk_urb(urb, udev, usb_fill_bulk_urb(urb, udev,
usb_sndbulkpipe(udev, es1->cport_out_endpoint), usb_sndbulkpipe(udev, es1->cport_out_endpoint),
buffer, gbuf->transfer_buffer_length + 1, transfer_buffer, transfer_buffer_size,
cport_out_callback, gbuf); cport_out_callback, hd);
retval = usb_submit_urb(urb, gfp_mask); retval = usb_submit_urb(urb, gfp_mask);
return retval; if (retval) {
pr_err("error %d submitting URB\n", retval);
return ERR_PTR(retval);
}
return urb;
} }
static void kill_gbuf(struct gbuf *gbuf) static void buffer_cancel(void *cookie)
{ {
struct urb *urb = gbuf->hcd_data; struct urb *urb = cookie;
if (!urb)
return;
/*
* We really should be defensive and track all outstanding
* (sent) buffers rather than trusting the cookie provided
* is valid. For the time being, this will do.
*/
usb_kill_urb(urb); usb_kill_urb(urb);
} }
static struct greybus_host_driver es1_driver = { static struct greybus_host_driver es1_driver = {
.hd_priv_size = sizeof(struct es1_ap_dev), .hd_priv_size = sizeof(struct es1_ap_dev),
.alloc_gbuf_data = alloc_gbuf_data, .buffer_alloc = buffer_alloc,
.free_gbuf_data = free_gbuf_data, .buffer_free = buffer_free,
.buffer_send = buffer_send,
.buffer_cancel = buffer_cancel,
.submit_svc = submit_svc, .submit_svc = submit_svc,
.submit_gbuf = submit_gbuf,
.kill_gbuf = kill_gbuf,
}; };
/* Common function to report consistent warnings based on URB status */ /* Common function to report consistent warnings based on URB status */
...@@ -329,7 +338,8 @@ static void ap_disconnect(struct usb_interface *interface) ...@@ -329,7 +338,8 @@ static void ap_disconnect(struct usb_interface *interface)
/* Callback for when we get a SVC message */ /* Callback for when we get a SVC message */
static void svc_in_callback(struct urb *urb) static void svc_in_callback(struct urb *urb)
{ {
struct es1_ap_dev *es1 = urb->context; struct greybus_host_device *hd = urb->context;
struct es1_ap_dev *es1 = hd_to_es1(hd);
struct device *dev = &urb->dev->dev; struct device *dev = &urb->dev->dev;
int status = check_urb_status(urb); int status = check_urb_status(urb);
int retval; int retval;
...@@ -355,8 +365,9 @@ static void svc_in_callback(struct urb *urb) ...@@ -355,8 +365,9 @@ static void svc_in_callback(struct urb *urb)
static void cport_in_callback(struct urb *urb) static void cport_in_callback(struct urb *urb)
{ {
struct greybus_host_device *hd = urb->context;
struct es1_ap_dev *es1 = hd_to_es1(hd);
struct device *dev = &urb->dev->dev; struct device *dev = &urb->dev->dev;
struct es1_ap_dev *es1 = urb->context;
int status = check_urb_status(urb); int status = check_urb_status(urb);
int retval; int retval;
u8 cport; u8 cport;
...@@ -396,15 +407,12 @@ static void cport_in_callback(struct urb *urb) ...@@ -396,15 +407,12 @@ static void cport_in_callback(struct urb *urb)
static void cport_out_callback(struct urb *urb) static void cport_out_callback(struct urb *urb)
{ {
struct gbuf *gbuf = urb->context; struct greybus_host_device *hd = urb->context;
struct es1_ap_dev *es1 = hd_to_es1(gbuf->hd); struct es1_ap_dev *es1 = hd_to_es1(hd);
unsigned long flags; unsigned long flags;
/* int status = check_urb_status(urb); */
int i; int i;
/* Record whether the transfer was successful */
gbuf->status = check_urb_status(urb);
gbuf->hcd_data = NULL;
/* /*
* See if this was an urb in our pool, if so mark it "free", otherwise * See if this was an urb in our pool, if so mark it "free", otherwise
* we need to free it ourselves. * we need to free it ourselves.
...@@ -423,6 +431,8 @@ static void cport_out_callback(struct urb *urb) ...@@ -423,6 +431,8 @@ static void cport_out_callback(struct urb *urb)
usb_free_urb(urb); usb_free_urb(urb);
/* /*
* Rest assured Greg, this craziness is getting fixed.
*
* Yes, you are right, we aren't telling anyone that the urb finished. * Yes, you are right, we aren't telling anyone that the urb finished.
* "That's crazy! How does this all even work?" you might be saying. * "That's crazy! How does this all even work?" you might be saying.
* The "magic" is the idea that greybus works on the "operation" level, * The "magic" is the idea that greybus works on the "operation" level,
...@@ -529,7 +539,7 @@ static int ap_probe(struct usb_interface *interface, ...@@ -529,7 +539,7 @@ static int ap_probe(struct usb_interface *interface,
usb_fill_int_urb(es1->svc_urb, udev, usb_fill_int_urb(es1->svc_urb, udev,
usb_rcvintpipe(udev, es1->svc_endpoint), usb_rcvintpipe(udev, es1->svc_endpoint),
es1->svc_buffer, ES1_SVC_MSG_SIZE, svc_in_callback, es1->svc_buffer, ES1_SVC_MSG_SIZE, svc_in_callback,
es1, svc_interval); hd, svc_interval);
retval = usb_submit_urb(es1->svc_urb, GFP_KERNEL); retval = usb_submit_urb(es1->svc_urb, GFP_KERNEL);
if (retval) if (retval)
goto error; goto error;
...@@ -549,7 +559,7 @@ static int ap_probe(struct usb_interface *interface, ...@@ -549,7 +559,7 @@ static int ap_probe(struct usb_interface *interface,
usb_fill_bulk_urb(urb, udev, usb_fill_bulk_urb(urb, udev,
usb_rcvbulkpipe(udev, es1->cport_in_endpoint), usb_rcvbulkpipe(udev, es1->cport_in_endpoint),
buffer, ES1_GBUF_MSG_SIZE, cport_in_callback, buffer, ES1_GBUF_MSG_SIZE, cport_in_callback,
es1); hd);
es1->cport_in_urb[i] = urb; es1->cport_in_urb[i] = urb;
es1->cport_in_buffer[i] = buffer; es1->cport_in_buffer[i] = buffer;
retval = usb_submit_urb(urb, GFP_KERNEL); retval = usb_submit_urb(urb, GFP_KERNEL);
......
...@@ -68,7 +68,9 @@ ...@@ -68,7 +68,9 @@
struct greybus_host_device; struct greybus_host_device;
struct svc_msg; struct svc_msg;
struct gbuf;
/* Buffers allocated from the host driver will be aligned to this multiple */
#define GB_BUFFER_ALIGN sizeof(u32)
/* Greybus "Host driver" structure, needed by a host controller driver to be /* Greybus "Host driver" structure, needed by a host controller driver to be
* able to handle both SVC control as well as "real" greybus messages * able to handle both SVC control as well as "real" greybus messages
...@@ -76,13 +78,13 @@ struct gbuf; ...@@ -76,13 +78,13 @@ struct gbuf;
struct greybus_host_driver { struct greybus_host_driver {
size_t hd_priv_size; size_t hd_priv_size;
int (*alloc_gbuf_data)(struct gbuf *gbuf, unsigned int size, void *(*buffer_alloc)(unsigned int size, gfp_t gfp_mask);
gfp_t gfp_mask); void (*buffer_free)(void *buffer);
void (*free_gbuf_data)(struct gbuf *gbuf); void *(*buffer_send)(struct greybus_host_device *hd, u16 dest_cport_id,
void *buffer, size_t buffer_size, gfp_t gfp_mask);
void (*buffer_cancel)(void *cookie);
int (*submit_svc)(struct svc_msg *svc_msg, int (*submit_svc)(struct svc_msg *svc_msg,
struct greybus_host_device *hd); struct greybus_host_device *hd);
int (*submit_gbuf)(struct gbuf *gbuf, gfp_t gfp_mask);
void (*kill_gbuf)(struct gbuf *gbuf);
}; };
struct greybus_host_device { struct greybus_host_device {
...@@ -153,8 +155,6 @@ int gb_ap_init(void); ...@@ -153,8 +155,6 @@ int gb_ap_init(void);
void gb_ap_exit(void); void gb_ap_exit(void);
int gb_debugfs_init(void); int gb_debugfs_init(void);
void gb_debugfs_cleanup(void); void gb_debugfs_cleanup(void);
int gb_gbuf_init(void);
void gb_gbuf_exit(void);
extern struct bus_type greybus_bus_type; extern struct bus_type greybus_bus_type;
extern const struct attribute_group *greybus_module_groups[]; extern const struct attribute_group *greybus_module_groups[];
......
...@@ -72,7 +72,7 @@ static void gb_pending_operation_insert(struct gb_operation *operation) ...@@ -72,7 +72,7 @@ static void gb_pending_operation_insert(struct gb_operation *operation)
spin_unlock_irq(&gb_operations_lock); spin_unlock_irq(&gb_operations_lock);
/* Store the operation id in the request header */ /* Store the operation id in the request header */
header = operation->request.gbuf.transfer_buffer; header = operation->request.buffer;
header->id = cpu_to_le16(operation->id); header->id = cpu_to_le16(operation->id);
} }
...@@ -103,20 +103,37 @@ gb_pending_operation_find(struct gb_connection *connection, u16 id) ...@@ -103,20 +103,37 @@ gb_pending_operation_find(struct gb_connection *connection, u16 id)
return found ? operation : NULL; return found ? operation : NULL;
} }
static int greybus_submit_gbuf(struct gbuf *gbuf, gfp_t gfp_mask) static int gb_message_send(struct gb_message *message, gfp_t gfp_mask)
{ {
gbuf->status = -EINPROGRESS; struct gb_connection *connection = message->operation->connection;
u16 dest_cport_id = connection->interface_cport_id;
return gbuf->hd->driver->submit_gbuf(gbuf, gfp_mask);
message->status = -EINPROGRESS;
message->cookie = connection->hd->driver->buffer_send(connection->hd,
dest_cport_id,
message->buffer,
message->buffer_size,
gfp_mask);
if (IS_ERR(message->cookie)) {
message->status = PTR_ERR(message->cookie);
message->cookie = NULL;
return message->status;
}
return 0;
} }
static void greybus_kill_gbuf(struct gbuf *gbuf) static void gb_message_cancel(struct gb_message *message)
{ {
if (gbuf->status != -EINPROGRESS) struct greybus_host_device *hd;
if (message->status != -EINPROGRESS)
return; return;
gbuf->hd->driver->kill_gbuf(gbuf); hd = message->operation->connection->hd;
hd->driver->buffer_cancel(message->cookie);
} }
/* /*
* An operations's response message has arrived. If no callback was * An operations's response message has arrived. If no callback was
* supplied it was submitted for asynchronous completion, so we notify * supplied it was submitted for asynchronous completion, so we notify
...@@ -139,7 +156,7 @@ int gb_operation_wait(struct gb_operation *operation) ...@@ -139,7 +156,7 @@ int gb_operation_wait(struct gb_operation *operation)
ret = wait_for_completion_interruptible(&operation->completion); ret = wait_for_completion_interruptible(&operation->completion);
/* If interrupted, cancel the in-flight buffer */ /* If interrupted, cancel the in-flight buffer */
if (ret < 0) if (ret < 0)
greybus_kill_gbuf(&operation->request.gbuf); gb_message_cancel(&operation->request);
return ret; return ret;
} }
...@@ -149,7 +166,7 @@ static void gb_operation_request_handle(struct gb_operation *operation) ...@@ -149,7 +166,7 @@ static void gb_operation_request_handle(struct gb_operation *operation)
struct gb_protocol *protocol = operation->connection->protocol; struct gb_protocol *protocol = operation->connection->protocol;
struct gb_operation_msg_hdr *header; struct gb_operation_msg_hdr *header;
header = operation->request.gbuf.transfer_buffer; header = operation->request.buffer;
/* /*
* If the protocol has no incoming request handler, report * If the protocol has no incoming request handler, report
...@@ -179,7 +196,7 @@ static void gb_operation_recv_work(struct work_struct *recv_work) ...@@ -179,7 +196,7 @@ static void gb_operation_recv_work(struct work_struct *recv_work)
bool incoming_request; bool incoming_request;
operation = container_of(recv_work, struct gb_operation, recv_work); operation = container_of(recv_work, struct gb_operation, recv_work);
incoming_request = operation->response.gbuf.transfer_buffer == NULL; incoming_request = operation->response.buffer == NULL;
if (incoming_request) if (incoming_request)
gb_operation_request_handle(operation); gb_operation_request_handle(operation);
gb_operation_complete(operation); gb_operation_complete(operation);
...@@ -213,16 +230,12 @@ static void operation_timeout(struct work_struct *work) ...@@ -213,16 +230,12 @@ static void operation_timeout(struct work_struct *work)
*/ */
static int gb_operation_message_init(struct gb_operation *operation, static int gb_operation_message_init(struct gb_operation *operation,
u8 type, size_t size, u8 type, size_t size,
bool request, bool data_out) bool request, gfp_t gfp_flags)
{ {
struct gb_connection *connection = operation->connection; struct gb_connection *connection = operation->connection;
struct greybus_host_device *hd = connection->hd; struct greybus_host_device *hd = connection->hd;
struct gb_message *message; struct gb_message *message;
struct gb_operation_msg_hdr *header; 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) if (size > GB_OPERATION_MESSAGE_SIZE_MAX)
return -E2BIG; return -E2BIG;
...@@ -234,22 +247,15 @@ static int gb_operation_message_init(struct gb_operation *operation, ...@@ -234,22 +247,15 @@ static int gb_operation_message_init(struct gb_operation *operation,
message = &operation->response; message = &operation->response;
type |= GB_OPERATION_TYPE_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;
gbuf->hd = hd; message->buffer = hd->driver->buffer_alloc(size, gfp_flags);
gbuf->dest_cport_id = dest_cport_id; if (!message->buffer)
gbuf->status = -EBADR; /* Initial value--means "never set" */ return -ENOMEM;
ret = hd->driver->alloc_gbuf_data(gbuf, size, gfp_flags); message->buffer_size = size;
if (ret) message->status = -EBADR; /* Initial value--means "never set" */
return ret;
/* Fill in the header structure */ /* Fill in the header structure */
header = (struct gb_operation_msg_hdr *)gbuf->transfer_buffer; header = message->buffer;
header->size = cpu_to_le16(size); header->size = cpu_to_le16(size);
header->id = 0; /* Filled in when submitted */ header->id = 0; /* Filled in when submitted */
header->type = type; header->type = type;
...@@ -262,9 +268,15 @@ static int gb_operation_message_init(struct gb_operation *operation, ...@@ -262,9 +268,15 @@ static int gb_operation_message_init(struct gb_operation *operation,
static void gb_operation_message_exit(struct gb_message *message) static void gb_operation_message_exit(struct gb_message *message)
{ {
struct greybus_host_device *hd;
hd = message->operation->connection->hd;
hd->driver->buffer_free(message->buffer);
message->operation = NULL; message->operation = NULL;
message->payload = NULL; message->payload = NULL;
message->gbuf.hd->driver->free_gbuf_data(&message->gbuf); message->buffer = NULL;
message->buffer_size = 0;
} }
/* /*
...@@ -298,13 +310,13 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection, ...@@ -298,13 +310,13 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection,
operation->connection = connection; operation->connection = connection;
ret = gb_operation_message_init(operation, type, request_size, ret = gb_operation_message_init(operation, type, request_size,
true, outgoing); true, gfp_flags);
if (ret) if (ret)
goto err_cache; goto err_cache;
if (outgoing) { if (outgoing) {
ret = gb_operation_message_init(operation, type, response_size, ret = gb_operation_message_init(operation, type, response_size,
false, false); false, GFP_KERNEL);
if (ret) if (ret)
goto err_request; goto err_request;
} }
...@@ -377,11 +389,11 @@ int gb_operation_request_send(struct gb_operation *operation, ...@@ -377,11 +389,11 @@ int gb_operation_request_send(struct gb_operation *operation,
* XXX * XXX
* I think the order of operations is going to be * I think the order of operations is going to be
* significant, and if so, we may need a mutex to surround * significant, and if so, we may need a mutex to surround
* setting the operation id and submitting the gbuf. * setting the operation id and submitting the buffer.
*/ */
operation->callback = callback; operation->callback = callback;
gb_pending_operation_insert(operation); gb_pending_operation_insert(operation);
ret = greybus_submit_gbuf(&operation->request.gbuf, GFP_KERNEL); ret = gb_message_send(&operation->request, GFP_KERNEL);
if (ret) if (ret)
return ret; return ret;
...@@ -418,12 +430,12 @@ int gb_operation_response_send(struct gb_operation *operation) ...@@ -418,12 +430,12 @@ int gb_operation_response_send(struct gb_operation *operation)
* data into the buffer and do remaining handling via a work queue. * data into the buffer and do remaining handling via a work queue.
* *
*/ */
void gb_connection_operation_recv(struct gb_connection *connection, void gb_connection_recv(struct gb_connection *connection,
void *data, size_t size) void *data, size_t size)
{ {
struct gb_operation_msg_hdr *header; struct gb_operation_msg_hdr *header;
struct gb_operation *operation; struct gb_operation *operation;
struct gbuf *gbuf; struct gb_message *message;
u16 msg_size; u16 msg_size;
if (connection->state != GB_CONNECTION_STATE_ENABLED) if (connection->state != GB_CONNECTION_STATE_ENABLED)
...@@ -446,8 +458,8 @@ void gb_connection_operation_recv(struct gb_connection *connection, ...@@ -446,8 +458,8 @@ void gb_connection_operation_recv(struct gb_connection *connection,
} }
cancel_delayed_work(&operation->timeout_work); cancel_delayed_work(&operation->timeout_work);
gb_pending_operation_remove(operation); gb_pending_operation_remove(operation);
gbuf = &operation->response.gbuf; message = &operation->response;
if (size > gbuf->transfer_buffer_length) { if (size > message->buffer_size) {
operation->result = GB_OP_OVERFLOW; operation->result = GB_OP_OVERFLOW;
gb_connection_err(connection, "recv buffer too small"); gb_connection_err(connection, "recv buffer too small");
return; return;
...@@ -461,10 +473,10 @@ void gb_connection_operation_recv(struct gb_connection *connection, ...@@ -461,10 +473,10 @@ void gb_connection_operation_recv(struct gb_connection *connection,
gb_connection_err(connection, "can't create operation"); gb_connection_err(connection, "can't create operation");
return; return;
} }
gbuf = &operation->request.gbuf; message = &operation->request;
} }
memcpy(gbuf->transfer_buffer, data, msg_size); memcpy(message->buffer, data, msg_size);
/* The rest will be handled in work queue context */ /* The rest will be handled in work queue context */
queue_work(gb_operation_recv_workqueue, &operation->recv_work); queue_work(gb_operation_recv_workqueue, &operation->recv_work);
...@@ -476,9 +488,9 @@ void gb_connection_operation_recv(struct gb_connection *connection, ...@@ -476,9 +488,9 @@ void gb_connection_operation_recv(struct gb_connection *connection,
void gb_operation_cancel(struct gb_operation *operation) void gb_operation_cancel(struct gb_operation *operation)
{ {
operation->canceled = true; operation->canceled = true;
greybus_kill_gbuf(&operation->request.gbuf); gb_message_cancel(&operation->request);
if (operation->response.gbuf.transfer_buffer) if (operation->response.buffer)
greybus_kill_gbuf(&operation->response.gbuf); gb_message_cancel(&operation->response);
} }
int gb_operation_init(void) int gb_operation_init(void)
......
...@@ -24,21 +24,16 @@ enum gb_operation_status { ...@@ -24,21 +24,16 @@ enum gb_operation_status {
GB_OP_TIMEOUT = 0xff, 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 { struct gb_message {
void *payload; void *payload;
struct gb_operation *operation; struct gb_operation *operation;
struct gbuf gbuf; int status;
void *buffer;
size_t buffer_size;
void *cookie;
}; };
/* /*
...@@ -87,7 +82,7 @@ struct gb_operation { ...@@ -87,7 +82,7 @@ struct gb_operation {
struct list_head links; /* connection->{operations,pending} */ struct list_head links; /* connection->{operations,pending} */
}; };
void gb_connection_operation_recv(struct gb_connection *connection, void gb_connection_recv(struct gb_connection *connection,
void *data, size_t size); void *data, size_t size);
struct gb_operation *gb_operation_create(struct gb_connection *connection, struct gb_operation *gb_operation_create(struct gb_connection *connection,
......
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