blob: 6f8873af09e0bbf1747725fd6b860f7227b165ea [file] [log] [blame]
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +08001/*
2 * Greybus gbuf handling
3 *
4 * Copyright 2014 Google Inc.
5 *
6 * Released under the GPLv2 only.
7 */
8
9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10
11#include <linux/types.h>
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/kernel.h>
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070015#include <linux/kref.h>
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +080016#include <linux/device.h>
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070017#include <linux/slab.h>
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +080018
19#include "greybus.h"
20
Greg Kroah-Hartman3e7736e2014-09-21 17:34:28 -070021static struct kmem_cache *gbuf_head_cache;
22
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070023/**
24 * greybus_alloc_gbuf - allocate a greybus buffer
25 *
Alex Elder778c69c2014-09-22 19:19:03 -050026 * @gmod: greybus device that wants to allocate this
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070027 * @cport: cport to send the data to
28 * @complete: callback when the gbuf is finished with
29 * @size: size of the buffer
30 * @gfp_mask: allocation mask
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070031 *
32 * TODO: someday it will be nice to handle DMA, but for now, due to the
33 * architecture we are stuck with, the greybus core has to allocate the buffer
34 * that the driver can then fill up with the data to be sent out. Curse
35 * hardware designers for this issue...
36 */
Alex Elderba993462014-11-17 08:08:43 -060037struct gbuf *greybus_alloc_gbuf(struct greybus_host_device *hd,
Alex Elder63921d82014-11-17 08:08:41 -060038 u16 dest_cport_id,
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070039 unsigned int size,
Alex Eldera77b0682014-11-06 07:01:03 -060040 gfp_t gfp_mask)
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +080041{
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070042 struct gbuf *gbuf;
43 int retval;
44
Alex Elderfdb594f2014-10-06 06:53:12 -050045 gbuf = kmem_cache_zalloc(gbuf_head_cache, gfp_mask);
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070046 if (!gbuf)
47 return NULL;
48
Alex Elderfdb594f2014-10-06 06:53:12 -050049 kref_init(&gbuf->kref);
Alex Elderba993462014-11-17 08:08:43 -060050 gbuf->hd = hd;
Alex Elder63921d82014-11-17 08:08:41 -060051 gbuf->dest_cport_id = dest_cport_id;
Alex Elderbedfdf32014-10-17 05:18:22 -050052 gbuf->status = -EBADR; /* Initial value--means "never set" */
Alex Elderfdb594f2014-10-06 06:53:12 -050053
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070054 /* Host controller specific allocation for the actual buffer */
Alex Elderef45fa32014-11-06 07:01:02 -060055 retval = hd->driver->alloc_gbuf_data(gbuf, size, gfp_mask);
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070056 if (retval) {
Alex Elderfdb594f2014-10-06 06:53:12 -050057 kmem_cache_free(gbuf_head_cache, gbuf);
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070058 return NULL;
59 }
60
61 return gbuf;
62}
63EXPORT_SYMBOL_GPL(greybus_alloc_gbuf);
64
65static DEFINE_MUTEX(gbuf_mutex);
66
67static void free_gbuf(struct kref *kref)
68{
69 struct gbuf *gbuf = container_of(kref, struct gbuf, kref);
70
Alex Elderba993462014-11-17 08:08:43 -060071 gbuf->hd->driver->free_gbuf_data(gbuf);
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070072
Greg Kroah-Hartman3e7736e2014-09-21 17:34:28 -070073 kmem_cache_free(gbuf_head_cache, gbuf);
Alex Elderad8cd0d62014-10-16 06:35:25 -050074 mutex_unlock(&gbuf_mutex);
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +080075}
76
77void greybus_free_gbuf(struct gbuf *gbuf)
78{
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070079 /* drop the reference count and get out of here */
80 kref_put_mutex(&gbuf->kref, free_gbuf, &gbuf_mutex);
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +080081}
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070082EXPORT_SYMBOL_GPL(greybus_free_gbuf);
83
84struct gbuf *greybus_get_gbuf(struct gbuf *gbuf)
85{
86 mutex_lock(&gbuf_mutex);
87 kref_get(&gbuf->kref);
88 mutex_unlock(&gbuf_mutex);
89 return gbuf;
90}
91EXPORT_SYMBOL_GPL(greybus_get_gbuf);
92
Greg Kroah-Hartmanf036e052014-09-19 19:13:33 -070093int greybus_submit_gbuf(struct gbuf *gbuf, gfp_t gfp_mask)
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +080094{
Alex Elderbedfdf32014-10-17 05:18:22 -050095 gbuf->status = -EINPROGRESS;
96
Alex Elderba993462014-11-17 08:08:43 -060097 return gbuf->hd->driver->submit_gbuf(gbuf, gfp_mask);
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +080098}
99
Greg Kroah-Hartman4afbba02014-10-27 14:01:06 +0800100void greybus_kill_gbuf(struct gbuf *gbuf)
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +0800101{
Greg Kroah-Hartmand8144882014-10-27 13:31:01 +0800102 if (gbuf->status != -EINPROGRESS)
Greg Kroah-Hartman4afbba02014-10-27 14:01:06 +0800103 return;
Greg Kroah-Hartmand8144882014-10-27 13:31:01 +0800104
Alex Elderba993462014-11-17 08:08:43 -0600105 gbuf->hd->driver->kill_gbuf(gbuf);
Greg Kroah-Hartmand5d19032014-08-11 19:03:20 +0800106}
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700107
Alex Elder1cfc6672014-09-30 19:25:21 -0500108void greybus_cport_in(struct greybus_host_device *hd, u16 cport_id,
109 u8 *data, size_t length)
Greg Kroah-Hartman80e04f02014-09-13 18:20:54 -0700110{
Alex Elder00d2e752014-10-06 06:53:09 -0500111 struct gb_connection *connection;
112
113 connection = gb_hd_connection_find(hd, cport_id);
114 if (!connection) {
115 dev_err(hd->parent,
116 "nonexistent connection (%zu bytes dropped)\n", length);
117 return;
118 }
Alex Elderd90c25b2014-10-16 06:35:33 -0500119 gb_connection_operation_recv(connection, data, length);
Greg Kroah-Hartman80e04f02014-09-13 18:20:54 -0700120}
Alex Elder0db32a62014-09-24 05:16:14 -0500121EXPORT_SYMBOL_GPL(greybus_cport_in);
Greg Kroah-Hartman80e04f02014-09-13 18:20:54 -0700122
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700123int gb_gbuf_init(void)
Greg Kroah-Hartman80e04f02014-09-13 18:20:54 -0700124{
Greg Kroah-Hartman3e7736e2014-09-21 17:34:28 -0700125 gbuf_head_cache = kmem_cache_create("gbuf_head_cache",
126 sizeof(struct gbuf), 0, 0, NULL);
Greg Kroah-Hartman80e04f02014-09-13 18:20:54 -0700127 return 0;
128}
129
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700130void gb_gbuf_exit(void)
Greg Kroah-Hartman80e04f02014-09-13 18:20:54 -0700131{
Greg Kroah-Hartman3e7736e2014-09-21 17:34:28 -0700132 kmem_cache_destroy(gbuf_head_cache);
Viresh Kumarf66832da2014-11-14 17:25:01 +0530133 gbuf_head_cache = NULL;
Greg Kroah-Hartman80e04f02014-09-13 18:20:54 -0700134}