]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - drivers/staging/unisys/uislib/uisutils.c
pinctrl: sirf: move sgpio lock into state container
[mirror_ubuntu-zesty-kernel.git] / drivers / staging / unisys / uislib / uisutils.c
1 /* uisutils.c
2 *
3 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14 * NON INFRINGEMENT. See the GNU General Public License for more
15 * details.
16 */
17
18 #include <linux/string.h>
19 #include <linux/slab.h>
20 #include <linux/types.h>
21 #include <linux/uuid.h>
22 #include <linux/spinlock.h>
23 #include <linux/list.h>
24 #include "uniklog.h"
25 #include "uisutils.h"
26 #include "version.h"
27 #include "vbushelper.h"
28 #include <linux/skbuff.h>
29 #ifdef CONFIG_HIGHMEM
30 #include <linux/highmem.h>
31 #endif
32
33 /* this is shorter than using __FILE__ (full path name) in
34 * debug/info/error messages
35 */
36 #define CURRENT_FILE_PC UISLIB_PC_uisutils_c
37 #define __MYFILE__ "uisutils.c"
38
39 /* exports */
40 atomic_t uisutils_registered_services = ATOMIC_INIT(0);
41 /* num registrations via
42 * uisctrl_register_req_handler() or
43 * uisctrl_register_req_handler_ex() */
44
45 /*****************************************************/
46 /* Utility functions */
47 /*****************************************************/
48
49 int
50 uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
51 char *format, ...)
52 {
53 va_list args;
54 int len;
55
56 DBGINF("buffer = 0x%p : *buffer = 0x%p.\n", buffer, *buffer);
57 va_start(args, format);
58 len = vsnprintf(*buffer, *buffer_remaining, format, args);
59 va_end(args);
60 if (len >= *buffer_remaining) {
61 *buffer += *buffer_remaining;
62 *total += *buffer_remaining;
63 *buffer_remaining = 0;
64 LOGERR("bytes remaining is too small!\n");
65 return -1;
66 }
67 *buffer_remaining -= len;
68 *buffer += len;
69 *total += len;
70 return len;
71 }
72 EXPORT_SYMBOL_GPL(uisutil_add_proc_line_ex);
73
74 int
75 uisctrl_register_req_handler(int type, void *fptr,
76 struct ultra_vbus_deviceinfo *chipset_driver_info)
77 {
78 LOGINF("type = %d, fptr = 0x%p.\n", type, fptr);
79
80 switch (type) {
81 case 2:
82 if (fptr) {
83 if (!virt_control_chan_func)
84 atomic_inc(&uisutils_registered_services);
85 virt_control_chan_func = fptr;
86 } else {
87 if (virt_control_chan_func)
88 atomic_dec(&uisutils_registered_services);
89 virt_control_chan_func = NULL;
90 }
91 break;
92
93 default:
94 LOGERR("invalid type %d.\n", type);
95 return 0;
96 }
97 if (chipset_driver_info)
98 bus_device_info_init(chipset_driver_info, "chipset", "uislib",
99 VERSION, NULL);
100
101 return 1;
102 }
103 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler);
104
105 int
106 uisctrl_register_req_handler_ex(uuid_le switch_uuid,
107 const char *switch_type_name,
108 int (*controlfunc)(struct io_msgs *),
109 unsigned long min_channel_bytes,
110 int (*server_channel_ok)(unsigned long channel_bytes),
111 int (*server_channel_init)(void *x,
112 unsigned char *client_str,
113 u32 client_str_len, u64 bytes),
114 struct ultra_vbus_deviceinfo *chipset_driver_info)
115 {
116 struct req_handler_info *req_handler;
117
118 LOGINF("type=%pUL, controlfunc=0x%p.\n",
119 &switch_uuid, controlfunc);
120 if (!controlfunc) {
121 LOGERR("%pUL: controlfunc must be supplied\n", &switch_uuid);
122 return 0;
123 }
124 if (!server_channel_ok) {
125 LOGERR("%pUL: Server_Channel_Ok must be supplied\n",
126 &switch_uuid);
127 return 0;
128 }
129 if (!server_channel_init) {
130 LOGERR("%pUL: Server_Channel_Init must be supplied\n",
131 &switch_uuid);
132 return 0;
133 }
134 req_handler = req_handler_add(switch_uuid,
135 switch_type_name,
136 controlfunc,
137 min_channel_bytes,
138 server_channel_ok, server_channel_init);
139 if (!req_handler) {
140 LOGERR("failed to add %pUL to server list\n", &switch_uuid);
141 return 0;
142 }
143
144 atomic_inc(&uisutils_registered_services);
145 if (chipset_driver_info) {
146 bus_device_info_init(chipset_driver_info, "chipset",
147 "uislib", VERSION, NULL);
148 return 1;
149 }
150
151 LOGERR("failed to register type %pUL.\n", &switch_uuid);
152 return 0;
153 }
154 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex);
155
156 int
157 uisctrl_unregister_req_handler_ex(uuid_le switch_uuid)
158 {
159 LOGINF("type=%pUL.\n", &switch_uuid);
160 if (req_handler_del(switch_uuid) < 0) {
161 LOGERR("failed to remove %pUL from server list\n",
162 &switch_uuid);
163 return 0;
164 }
165 atomic_dec(&uisutils_registered_services);
166 return 1;
167 }
168 EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex);
169
170 /*
171 * unsigned int uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
172 * void *skb_in,
173 * unsigned int firstfraglen,
174 * unsigned int frags_max,
175 * struct phys_info frags[])
176 *
177 * calling_ctx - input - a string that is displayed to show
178 * who called * this func
179 * void *skb_in - skb whose frag info we're copying type is hidden so we
180 * don't need to include skbbuff in uisutils.h which is
181 * included in non-networking code.
182 * unsigned int firstfraglen - input - length of first fragment in skb
183 * unsigned int frags_max - input - max len of frags array
184 * struct phys_info frags[] - output - frags array filled in on output
185 * return value indicates number of
186 * entries filled in frags
187 */
188 unsigned int
189 uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in,
190 unsigned int firstfraglen,
191 unsigned int frags_max,
192 struct phys_info frags[])
193 {
194 unsigned int count = 0, ii, size, offset = 0, numfrags;
195 struct sk_buff *skb = skb_in;
196
197 numfrags = skb_shinfo(skb)->nr_frags;
198
199 while (firstfraglen) {
200 if (count == frags_max) {
201 LOGERR("%s frags array too small: max:%d count:%d\n",
202 calling_ctx, frags_max, count);
203 return -1; /* failure */
204 }
205 frags[count].pi_pfn =
206 page_to_pfn(virt_to_page(skb->data + offset));
207 frags[count].pi_off =
208 (unsigned long)(skb->data + offset) & PI_PAGE_MASK;
209 size =
210 min(firstfraglen,
211 (unsigned int)(PI_PAGE_SIZE - frags[count].pi_off));
212 /* can take smallest of firstfraglen(what's left) OR
213 * bytes left in the page
214 */
215 frags[count].pi_len = size;
216 firstfraglen -= size;
217 offset += size;
218 count++;
219 }
220 if (!numfrags)
221 goto dolist;
222
223 if ((count + numfrags) > frags_max) {
224 LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n",
225 calling_ctx, frags_max, count + numfrags);
226 return -1; /* failure */
227 }
228
229 for (ii = 0; ii < numfrags; ii++) {
230 count = add_physinfo_entries(page_to_pfn(
231 skb_frag_page(&skb_shinfo(skb)->frags[ii])),
232 skb_shinfo(skb)->frags[ii].
233 page_offset,
234 skb_shinfo(skb)->frags[ii].
235 size, count, frags_max,
236 frags);
237 if (count == 0) {
238 LOGERR("**** FAILED to add physinfo entries\n");
239 return -1; /* failure */
240 }
241 }
242
243 dolist: if (skb_shinfo(skb)->frag_list) {
244 struct sk_buff *skbinlist;
245 int c;
246
247 for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist;
248 skbinlist = skbinlist->next) {
249 c = uisutil_copy_fragsinfo_from_skb("recursive",
250 skbinlist,
251 skbinlist->len - skbinlist->data_len,
252 frags_max - count,
253 &frags[count]);
254 if (c == -1) {
255 LOGERR("**** FAILED recursive call failed\n");
256 return -1;
257 }
258 count += c;
259 }
260 }
261 return count;
262 }
263 EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb);
264
265 static LIST_HEAD(req_handler_info_list); /* list of struct req_handler_info */
266 static DEFINE_SPINLOCK(req_handler_info_list_lock);
267
268 struct req_handler_info *
269 req_handler_add(uuid_le switch_uuid,
270 const char *switch_type_name,
271 int (*controlfunc)(struct io_msgs *),
272 unsigned long min_channel_bytes,
273 int (*server_channel_ok)(unsigned long channel_bytes),
274 int (*server_channel_init)
275 (void *x, unsigned char *clientstr, u32 clientstr_len,
276 u64 bytes))
277 {
278 struct req_handler_info *rc = NULL;
279
280 rc = kzalloc(sizeof(*rc), GFP_ATOMIC);
281 if (!rc)
282 return NULL;
283 rc->switch_uuid = switch_uuid;
284 rc->controlfunc = controlfunc;
285 rc->min_channel_bytes = min_channel_bytes;
286 rc->server_channel_ok = server_channel_ok;
287 rc->server_channel_init = server_channel_init;
288 if (switch_type_name)
289 strncpy(rc->switch_type_name, switch_type_name,
290 sizeof(rc->switch_type_name) - 1);
291 spin_lock(&req_handler_info_list_lock);
292 list_add_tail(&rc->list_link, &req_handler_info_list);
293 spin_unlock(&req_handler_info_list_lock);
294
295 return rc;
296 }
297
298 struct req_handler_info *
299 req_handler_find(uuid_le switch_uuid)
300 {
301 struct list_head *lelt, *tmp;
302 struct req_handler_info *entry = NULL;
303
304 spin_lock(&req_handler_info_list_lock);
305 list_for_each_safe(lelt, tmp, &req_handler_info_list) {
306 entry = list_entry(lelt, struct req_handler_info, list_link);
307 if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
308 spin_unlock(&req_handler_info_list_lock);
309 return entry;
310 }
311 }
312 spin_unlock(&req_handler_info_list_lock);
313 return NULL;
314 }
315
316 int
317 req_handler_del(uuid_le switch_uuid)
318 {
319 struct list_head *lelt, *tmp;
320 struct req_handler_info *entry = NULL;
321 int rc = -1;
322
323 spin_lock(&req_handler_info_list_lock);
324 list_for_each_safe(lelt, tmp, &req_handler_info_list) {
325 entry = list_entry(lelt, struct req_handler_info, list_link);
326 if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
327 list_del(lelt);
328 kfree(entry);
329 rc++;
330 }
331 }
332 spin_unlock(&req_handler_info_list_lock);
333 return rc;
334 }