blob: eed77c3f3a7fd4f9af811a8267f19beaa5520412 [file] [log] [blame]
Alex Elder4ccb6b72014-10-28 19:36:00 -05001/*
2 * Greybus protocol handling
3 *
Alex Elderd3d2bea2015-03-26 21:25:01 -05004 * Copyright 2014-2015 Google Inc.
5 * Copyright 2014-2015 Linaro Ltd.
Alex Elder4ccb6b72014-10-28 19:36:00 -05006 *
7 * Released under the GPLv2 only.
8 */
9
Greg Kroah-Hartman7422a1e2014-12-24 13:01:45 -080010#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
Alex Elder4ccb6b72014-10-28 19:36:00 -050012#include "greybus.h"
13
14/* Global list of registered protocols */
15static DEFINE_SPINLOCK(gb_protocols_lock);
16static LIST_HEAD(gb_protocols);
17
18/* Caller must hold gb_protocols_lock */
Viresh Kumar8fd46582015-05-20 16:47:59 +053019static struct gb_protocol *gb_protocol_find(u8 id, u8 major, u8 minor)
Alex Elder4ccb6b72014-10-28 19:36:00 -050020{
21 struct gb_protocol *protocol;
22
Alex Elderdbb88942014-11-05 16:12:52 -060023 list_for_each_entry(protocol, &gb_protocols, links) {
24 if (protocol->id < id)
25 continue;
26 if (protocol->id > id)
27 break;
28
29 if (protocol->major > major)
30 continue;
31 if (protocol->major < major)
32 break;
33
34 if (protocol->minor > minor)
35 continue;
36 if (protocol->minor < minor)
37 break;
38
39 return protocol;
40 }
Alex Elder4ccb6b72014-10-28 19:36:00 -050041 return NULL;
42}
43
Greg Kroah-Hartman12a5dfc2014-12-24 13:01:40 -080044int __gb_protocol_register(struct gb_protocol *protocol, struct module *module)
Alex Elder4ccb6b72014-10-28 19:36:00 -050045{
Alex Elder4ccb6b72014-10-28 19:36:00 -050046 struct gb_protocol *existing;
Alex Elder19d03de2014-11-05 16:12:53 -060047 u8 id = protocol->id;
48 u8 major = protocol->major;
49 u8 minor = protocol->minor;
Alex Elder4ccb6b72014-10-28 19:36:00 -050050
Greg Kroah-Hartman12a5dfc2014-12-24 13:01:40 -080051 protocol->owner = module;
52
Greg Kroah-Hartman6869eb52015-01-23 10:06:24 +080053 /*
54 * The protocols list is sorted first by protocol id (low to
55 * high), then by major version (high to low), and finally
56 * by minor version (high to low). Searching only by
57 * protocol id will produce the newest implemented version
58 * of the protocol.
59 */
Alex Elder4ccb6b72014-10-28 19:36:00 -050060 spin_lock_irq(&gb_protocols_lock);
Alex Elder4ccb6b72014-10-28 19:36:00 -050061
Greg Kroah-Hartman6869eb52015-01-23 10:06:24 +080062 list_for_each_entry(existing, &gb_protocols, links) {
63 if (existing->id < id)
64 continue;
65 if (existing->id > id)
66 break;
67
68 if (existing->major > major)
69 continue;
70 if (existing->major < major)
71 break;
72
73 if (existing->minor > minor)
74 continue;
75 if (existing->minor < minor)
76 break;
77
78 /* A matching protocol has already been registered */
Alex Elderdbb88942014-11-05 16:12:52 -060079 spin_unlock_irq(&gb_protocols_lock);
Greg Kroah-Hartman6869eb52015-01-23 10:06:24 +080080
Greg Kroah-Hartman7c7d5b92014-12-23 15:16:51 -080081 return -EEXIST;
Alex Elder4ccb6b72014-10-28 19:36:00 -050082 }
83
Alex Elderdbb88942014-11-05 16:12:52 -060084 /*
85 * We need to insert the protocol here, before the existing one
86 * (or before the head if we searched the whole list)
87 */
Greg Kroah-Hartmanc1a0a8f2015-01-23 10:05:58 +080088 list_add_tail(&protocol->links, &existing->links);
Alex Elderdbb88942014-11-05 16:12:52 -060089 spin_unlock_irq(&gb_protocols_lock);
90
Greg Kroah-Hartman7422a1e2014-12-24 13:01:45 -080091 pr_info("Registered %s protocol.\n", protocol->name);
92
Greg Kroah-Hartmanfb69cb52014-12-23 15:16:53 -080093 /*
94 * Go try to bind any unbound connections, as we have a
95 * new protocol in the system
96 */
97 gb_bundle_bind_protocols();
98
Greg Kroah-Hartman7c7d5b92014-12-23 15:16:51 -080099 return 0;
Alex Elder4ccb6b72014-10-28 19:36:00 -0500100}
Greg Kroah-Hartman12a5dfc2014-12-24 13:01:40 -0800101EXPORT_SYMBOL_GPL(__gb_protocol_register);
Alex Elder4ccb6b72014-10-28 19:36:00 -0500102
Alex Elder19d03de2014-11-05 16:12:53 -0600103/*
104 * De-register a previously registered protocol.
105 *
106 * XXX Currently this fails (and reports an error to the caller) if
107 * XXX the protocol is currently in use. We may want to forcefully
108 * XXX kill off a protocol and all its active users at some point.
Viresh Kumar696e0cc2014-11-21 11:26:30 +0530109 * XXX But I think that's better handled by quiescing modules that
Alex Elder19d03de2014-11-05 16:12:53 -0600110 * XXX have users and having those users drop their reference.
111 *
112 * Returns true if successful, false otherwise.
113 */
Greg Kroah-Hartman7c7d5b92014-12-23 15:16:51 -0800114int gb_protocol_deregister(struct gb_protocol *protocol)
Alex Elder4ccb6b72014-10-28 19:36:00 -0500115{
Alex Elderdbb88942014-11-05 16:12:52 -0600116 u8 protocol_count = 0;
Alex Elder0e447652014-11-05 16:12:51 -0600117
Greg Kroah-Hartman7c7d5b92014-12-23 15:16:51 -0800118 if (!protocol)
119 return 0;
120
Alex Elder4ccb6b72014-10-28 19:36:00 -0500121 spin_lock_irq(&gb_protocols_lock);
Viresh Kumar8fd46582015-05-20 16:47:59 +0530122 protocol = gb_protocol_find(protocol->id, protocol->major,
123 protocol->minor);
Alex Elder0e447652014-11-05 16:12:51 -0600124 if (protocol) {
125 protocol_count = protocol->count;
126 if (!protocol_count)
127 list_del(&protocol->links);
128 }
Alex Elder4ccb6b72014-10-28 19:36:00 -0500129 spin_unlock_irq(&gb_protocols_lock);
Alex Elder4ccb6b72014-10-28 19:36:00 -0500130
Greg Kroah-Hartman7422a1e2014-12-24 13:01:45 -0800131 if (protocol)
132 pr_info("Deregistered %s protocol.\n", protocol->name);
133
Alex Elder0e447652014-11-05 16:12:51 -0600134 return protocol && !protocol_count;
Alex Elder4ccb6b72014-10-28 19:36:00 -0500135}
Greg Kroah-Hartmandf469a92014-12-23 15:16:52 -0800136EXPORT_SYMBOL_GPL(gb_protocol_deregister);
Alex Elder4ccb6b72014-10-28 19:36:00 -0500137
Alex Elder0e447652014-11-05 16:12:51 -0600138/* Returns the requested protocol if available, or a null pointer */
139struct gb_protocol *gb_protocol_get(u8 id, u8 major, u8 minor)
Alex Elder4ccb6b72014-10-28 19:36:00 -0500140{
141 struct gb_protocol *protocol;
Alex Elder0e447652014-11-05 16:12:51 -0600142 u8 protocol_count;
Alex Elder4ccb6b72014-10-28 19:36:00 -0500143
144 spin_lock_irq(&gb_protocols_lock);
Viresh Kumar8fd46582015-05-20 16:47:59 +0530145 protocol = gb_protocol_find(id, major, minor);
Alex Elder0e447652014-11-05 16:12:51 -0600146 if (protocol) {
Greg Kroah-Hartman12a5dfc2014-12-24 13:01:40 -0800147 if (!try_module_get(protocol->owner)) {
148 protocol = NULL;
149 } else {
150 protocol_count = protocol->count;
151 if (protocol_count != U8_MAX)
152 protocol->count++;
153 }
Alex Elder0e447652014-11-05 16:12:51 -0600154 }
Alex Elder4ccb6b72014-10-28 19:36:00 -0500155 spin_unlock_irq(&gb_protocols_lock);
Alex Elder4ccb6b72014-10-28 19:36:00 -0500156
Alex Elder0e447652014-11-05 16:12:51 -0600157 if (protocol)
158 WARN_ON(protocol_count == U8_MAX);
159 else
160 pr_err("protocol id %hhu version %hhu.%hhu not found\n",
161 id, major, minor);
162
163 return protocol;
Alex Elder4ccb6b72014-10-28 19:36:00 -0500164}
165
Viresh Kumar36e79de2015-01-21 18:12:36 +0530166int gb_protocol_get_version(struct gb_connection *connection, int type,
167 void *request, int request_size,
168 struct gb_protocol_version_response *response,
169 __u8 major)
170{
171 int retval;
172
173 retval = gb_operation_sync(connection, type, request, request_size,
174 response, sizeof(*response));
175 if (retval)
176 return retval;
177
178 if (response->major > major) {
179 dev_err(&connection->dev,
180 "unsupported major version (%hhu > %hhu)\n",
181 response->major, major);
182 return -ENOTSUPP;
183 }
184
185 dev_dbg(&connection->dev, "version_major = %u version_minor = %u\n",
186 response->major, response->minor);
187
188 return 0;
189}
190EXPORT_SYMBOL_GPL(gb_protocol_get_version);
191
Alex Elder0e447652014-11-05 16:12:51 -0600192void gb_protocol_put(struct gb_protocol *protocol)
Alex Elder4ccb6b72014-10-28 19:36:00 -0500193{
Alex Elderd3d2bea2015-03-26 21:25:01 -0500194 u8 id;
Greg Kroah-Hartman23ad7bb2014-12-24 13:12:10 -0800195 u8 major;
196 u8 minor;
Alex Elder0e447652014-11-05 16:12:51 -0600197 u8 protocol_count;
Alex Elder4ccb6b72014-10-28 19:36:00 -0500198
Greg Kroah-Hartman23ad7bb2014-12-24 13:12:10 -0800199 if (!protocol)
200 return;
201
Alex Elderd3d2bea2015-03-26 21:25:01 -0500202 id = protocol->id;
Greg Kroah-Hartman23ad7bb2014-12-24 13:12:10 -0800203 major = protocol->major;
204 minor = protocol->minor;
205
Alex Elder4ccb6b72014-10-28 19:36:00 -0500206 spin_lock_irq(&gb_protocols_lock);
Viresh Kumar8fd46582015-05-20 16:47:59 +0530207 protocol = gb_protocol_find(id, major, minor);
Alex Elder0e447652014-11-05 16:12:51 -0600208 if (protocol) {
209 protocol_count = protocol->count;
210 if (protocol_count)
211 protocol->count--;
Greg Kroah-Hartman12a5dfc2014-12-24 13:01:40 -0800212 module_put(protocol->owner);
Alex Elder0e447652014-11-05 16:12:51 -0600213 }
Alex Elder4ccb6b72014-10-28 19:36:00 -0500214 spin_unlock_irq(&gb_protocols_lock);
Alex Elder0e447652014-11-05 16:12:51 -0600215 if (protocol)
216 WARN_ON(!protocol_count);
217 else
218 pr_err("protocol id %hhu version %hhu.%hhu not found\n",
Alex Elderd3d2bea2015-03-26 21:25:01 -0500219 id, major, minor);
Alex Elder4ccb6b72014-10-28 19:36:00 -0500220}