CPC comes with its own header, that is not yet implemented. Without skb, the CPC host device drivers have to get two pointers to get a full packet: one pointer to the CPC header and one pointer to the GB message. In order to make their implementations simpler, convert the GB message into an SKB.
Signed-off-by: Damien Riégel damien.riegel@silabs.com --- drivers/greybus/cpc/cpc.h | 11 +++++++++- drivers/greybus/cpc/cport.c | 11 ++++++++-- drivers/greybus/cpc/host.c | 41 ++++++++++++++++++++++++++++++++++--- drivers/greybus/cpc/host.h | 7 ++++--- 4 files changed, 61 insertions(+), 9 deletions(-)
diff --git a/drivers/greybus/cpc/cpc.h b/drivers/greybus/cpc/cpc.h index 85d02954307..7e032f6cf50 100644 --- a/drivers/greybus/cpc/cpc.h +++ b/drivers/greybus/cpc/cpc.h @@ -24,6 +24,15 @@ struct cpc_cport { struct cpc_cport *cpc_cport_alloc(u16 cport_id, gfp_t gfp_mask); void cpc_cport_release(struct cpc_cport *cport);
-int cpc_cport_message_send(struct cpc_cport *cport, struct gb_message *message, gfp_t gfp_mask); +int cpc_cport_transmit(struct cpc_cport *cport, struct sk_buff *skb); + +struct cpc_skb_cb { + struct cpc_cport *cport; + + /* Keep track of the GB message the skb originates from */ + struct gb_message *gb_message; +}; + +#define CPC_SKB_CB(__skb) ((struct cpc_skb_cb *)&((__skb)->cb[0]))
#endif diff --git a/drivers/greybus/cpc/cport.c b/drivers/greybus/cpc/cport.c index 88bdb2f8182..ed0b8e8b0d7 100644 --- a/drivers/greybus/cpc/cport.c +++ b/drivers/greybus/cpc/cport.c @@ -31,7 +31,14 @@ void cpc_cport_release(struct cpc_cport *cport) kfree(cport); }
-int cpc_cport_message_send(struct cpc_cport *cport, struct gb_message *message, gfp_t gfp_mask) +/** + * cpc_cport_transmit() - Transmit skb over cport. + * @cport: cport. + * @skb: skb to be transmitted. + */ +int cpc_cport_transmit(struct cpc_cport *cport, struct sk_buff *skb) { - return cport->cpc_hd->driver->message_send(cport->cpc_hd, cport->id, message, gfp_mask); + struct cpc_host_device *cpc_hd = cport->cpc_hd; + + return cpc_hd_send_skb(cpc_hd, skb); } diff --git a/drivers/greybus/cpc/host.c b/drivers/greybus/cpc/host.c index 033ff7f0184..2ca938c2b48 100644 --- a/drivers/greybus/cpc/host.c +++ b/drivers/greybus/cpc/host.c @@ -6,6 +6,7 @@ #include <linux/err.h> #include <linux/greybus.h> #include <linux/module.h> +#include <linux/skbuff.h>
#include "cpc.h" #include "host.h" @@ -39,6 +40,8 @@ static int cpc_hd_message_send(struct cpc_host_device *cpc_hd, u16 cport_id, struct gb_message *message, gfp_t gfp_mask) { struct cpc_cport *cport; + struct sk_buff *skb; + unsigned int size;
cport = cpc_hd_get_cport(cpc_hd, cport_id); if (!cport) { @@ -46,7 +49,18 @@ static int cpc_hd_message_send(struct cpc_host_device *cpc_hd, u16 cport_id, return -EINVAL; }
- return cpc_cport_message_send(cport, message, gfp_mask); + size = sizeof(*message->header) + message->payload_size; + skb = alloc_skb(size, gfp_mask); + if (!skb) + return -ENOMEM; + + /* Header and payload are already contiguous in Greybus message */ + skb_put_data(skb, message->buffer, sizeof(*message->header) + message->payload_size); + + CPC_SKB_CB(skb)->cport = cport; + CPC_SKB_CB(skb)->gb_message = message; + + return cpc_cport_transmit(cport, skb); }
static int cpc_hd_cport_allocate(struct cpc_host_device *cpc_hd, int cport_id, unsigned long flags) @@ -144,8 +158,8 @@ struct cpc_host_device *cpc_hd_create(struct cpc_hd_driver *driver, struct devic struct cpc_host_device *cpc_hd; struct gb_host_device *hd;
- if ((!driver->message_send) || (!driver->message_cancel)) { - dev_err(parent, "missing mandatory callbacks\n"); + if (!driver->transmit) { + dev_err(parent, "missing mandatory callback\n"); return ERR_PTR(-EINVAL); }
@@ -181,12 +195,33 @@ void cpc_hd_del(struct cpc_host_device *cpc_hd) } EXPORT_SYMBOL_GPL(cpc_hd_del);
+void cpc_hd_message_sent(struct sk_buff *skb, int status) +{ + struct cpc_host_device *cpc_hd = CPC_SKB_CB(skb)->cport->cpc_hd; + struct gb_host_device *hd = cpc_hd->gb_hd; + + greybus_message_sent(hd, CPC_SKB_CB(skb)->gb_message, status); +} +EXPORT_SYMBOL_GPL(cpc_hd_message_sent); + void cpc_hd_rcvd(struct cpc_host_device *cpc_hd, u16 cport_id, u8 *data, size_t length) { greybus_data_rcvd(cpc_hd->gb_hd, cport_id, data, length); } EXPORT_SYMBOL_GPL(cpc_hd_rcvd);
+/** + * cpc_hd_send_skb() - Queue a socket buffer for transmission. + * @cpc_hd: Host device to send SKB over. + * @skb: SKB to send. + */ +int cpc_hd_send_skb(struct cpc_host_device *cpc_hd, struct sk_buff *skb) +{ + const struct cpc_hd_driver *drv = cpc_hd->driver; + + return drv->transmit(cpc_hd, skb); +} + MODULE_DESCRIPTION("Greybus over CPC"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Silicon Laboratories, Inc."); diff --git a/drivers/greybus/cpc/host.h b/drivers/greybus/cpc/host.h index 1c168cdd2bf..104d61e3bc5 100644 --- a/drivers/greybus/cpc/host.h +++ b/drivers/greybus/cpc/host.h @@ -18,9 +18,7 @@ struct cpc_cport; struct cpc_host_device;
struct cpc_hd_driver { - int (*message_send)(struct cpc_host_device *hd, u16 dest_cport_id, - struct gb_message *message, gfp_t gfp_mask); - void (*message_cancel)(struct gb_message *message); + int (*transmit)(struct cpc_host_device *hd, struct sk_buff *skb); };
/** @@ -48,5 +46,8 @@ int cpc_hd_add(struct cpc_host_device *cpc_hd); void cpc_hd_put(struct cpc_host_device *cpc_hd); void cpc_hd_del(struct cpc_host_device *cpc_hd); void cpc_hd_rcvd(struct cpc_host_device *cpc_hd, u16 cport_id, u8 *data, size_t length); +void cpc_hd_message_sent(struct sk_buff *skb, int status); + +int cpc_hd_send_skb(struct cpc_host_device *cpc_hd, struct sk_buff *skb);
#endif