greybus: fix host-device buffer constraints

Host devices impose buffer-size constraints on Greybus core which are
taken into account when allocating messages.

Make sure to verify these constraints when the host device is allocated,
rather than when the first message is allocated.

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-05-19 11:22:43 +02:00 committed by Greg Kroah-Hartman
parent d966820f2c
commit d933667a1e
6 changed files with 19 additions and 57 deletions

View File

@ -173,7 +173,8 @@ static void free_hd(struct kref *kref)
}
struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
struct device *parent)
struct device *parent,
size_t buffer_size_max)
{
struct greybus_host_device *hd;
@ -187,6 +188,16 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
return NULL;
}
/*
* Make sure to never allocate messages larger than what the Greybus
* protocol supports.
*/
if (buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) {
dev_warn(parent, "limiting buffer size to %u\n",
GB_OPERATION_MESSAGE_SIZE_MAX);
buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX;
}
hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
if (!hd)
return NULL;
@ -197,6 +208,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
INIT_LIST_HEAD(&hd->interfaces);
INIT_LIST_HEAD(&hd->connections);
ida_init(&hd->cport_id_map);
hd->buffer_size_max = buffer_size_max;
hd->endo = gb_endo_create(hd);
if (!hd->endo) {

View File

@ -98,22 +98,6 @@ static void cport_out_callback(struct urb *urb);
static void usb_log_enable(struct es1_ap_dev *es1);
static void usb_log_disable(struct es1_ap_dev *es1);
/*
* Buffer constraints for the host driver.
*
* A "buffer" is used to hold data to be transferred for Greybus by
* the host driver. A buffer is represented by a "buffer pointer",
* which defines a region of memory used by the host driver for
* transferring the data. When Greybus allocates a buffer, it must
* do so subject to the constraints associated with the host driver.
*
* size_max: The maximum size of a buffer
*/
static void hd_buffer_constraints(struct greybus_host_device *hd)
{
hd->buffer_size_max = ES1_GBUF_MSG_SIZE_MAX;
}
#define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */
static int submit_svc(struct svc_msg *svc_msg, struct greybus_host_device *hd)
{
@ -571,15 +555,12 @@ static int ap_probe(struct usb_interface *interface,
udev = usb_get_dev(interface_to_usbdev(interface));
hd = greybus_create_hd(&es1_driver, &udev->dev);
hd = greybus_create_hd(&es1_driver, &udev->dev, ES1_GBUF_MSG_SIZE_MAX);
if (!hd) {
usb_put_dev(udev);
return -ENOMEM;
}
/* Fill in the buffer allocation constraints */
hd_buffer_constraints(hd);
es1 = hd_to_es1(hd);
es1->hd = hd;
es1->usb_intf = interface;

View File

@ -98,22 +98,6 @@ static void cport_out_callback(struct urb *urb);
static void usb_log_enable(struct es1_ap_dev *es1);
static void usb_log_disable(struct es1_ap_dev *es1);
/*
* Buffer constraints for the host driver.
*
* A "buffer" is used to hold data to be transferred for Greybus by
* the host driver. A buffer is represented by a "buffer pointer",
* which defines a region of memory used by the host driver for
* transferring the data. When Greybus allocates a buffer, it must
* do so subject to the constraints associated with the host driver.
*
* size_max: The maximum size of a buffer
*/
static void hd_buffer_constraints(struct greybus_host_device *hd)
{
hd->buffer_size_max = ES1_GBUF_MSG_SIZE_MAX;
}
#define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */
static int submit_svc(struct svc_msg *svc_msg, struct greybus_host_device *hd)
{
@ -571,15 +555,12 @@ static int ap_probe(struct usb_interface *interface,
udev = usb_get_dev(interface_to_usbdev(interface));
hd = greybus_create_hd(&es1_driver, &udev->dev);
hd = greybus_create_hd(&es1_driver, &udev->dev, ES1_GBUF_MSG_SIZE_MAX);
if (!hd) {
usb_put_dev(udev);
return -ENOMEM;
}
/* Fill in the buffer allocation constraints */
hd_buffer_constraints(hd);
es1 = hd_to_es1(hd);
es1->hd = hd;
es1->usb_intf = interface;

View File

@ -105,7 +105,8 @@ struct greybus_host_device {
};
struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *hd,
struct device *parent);
struct device *parent,
size_t buffer_size_max);
void greybus_remove_hd(struct greybus_host_device *hd);
struct greybus_driver {

View File

@ -17,12 +17,6 @@
/* The default amount of time a request is given to complete */
#define OPERATION_TIMEOUT_DEFAULT 1000 /* milliseconds */
/*
* 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
static struct kmem_cache *gb_operation_cache;
static struct kmem_cache *gb_message_cache;
@ -282,12 +276,6 @@ gb_operation_message_alloc(struct greybus_host_device *hd, u8 type,
struct gb_operation_msg_hdr *header;
size_t message_size = payload_size + sizeof(*header);
if (hd->buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) {
pr_warn("limiting buffer size to %u\n",
GB_OPERATION_MESSAGE_SIZE_MAX);
hd->buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX;
}
if (message_size > hd->buffer_size_max) {
pr_warn("requested message size too big (%zu > %zu)\n",
message_size, hd->buffer_size_max);
@ -936,9 +924,6 @@ EXPORT_SYMBOL_GPL(gb_operation_sync);
int gb_operation_init(void)
{
BUILD_BUG_ON(GB_OPERATION_MESSAGE_SIZE_MAX >
U16_MAX - sizeof(struct gb_operation_msg_hdr));
gb_message_cache = kmem_cache_create("gb_message_cache",
sizeof(struct gb_message), 0, 0, NULL);
if (!gb_message_cache)

View File

@ -69,6 +69,8 @@ struct gb_operation_msg_hdr {
__u8 pad[2]; /* must be zero (ignore when read) */
} __aligned(sizeof(u64));
#define GB_OPERATION_MESSAGE_SIZE_MAX 4096
/*
* Protocol code should only examine the payload and payload_size
* fields. All other fields are intended to be private to the