• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/uuid.h>
29 #include <linux/skbuff.h>
30 #include <linux/uuid.h>
31 #ifdef CONFIG_HIGHMEM
32 #include <linux/highmem.h>
33 #endif
34 
35 /* this is shorter than using __FILE__ (full path name) in
36  * debug/info/error messages
37  */
38 #define CURRENT_FILE_PC UISLIB_PC_uisutils_c
39 #define __MYFILE__ "uisutils.c"
40 
41 /* exports */
42 atomic_t UisUtils_Registered_Services = ATOMIC_INIT(0);
43 					/* num registrations via
44 					 * uisctrl_register_req_handler() or
45 					 * uisctrl_register_req_handler_ex() */
46 
47 
48 /*****************************************************/
49 /* Utility functions                                 */
50 /*****************************************************/
51 
52 int
uisutil_add_proc_line_ex(int * total,char ** buffer,int * buffer_remaining,char * format,...)53 uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
54 		      char *format, ...)
55 {
56 	va_list args;
57 	int len;
58 
59 	DBGINF("buffer = 0x%p : *buffer = 0x%p.\n", buffer, *buffer);
60 	va_start(args, format);
61 	len = vsnprintf(*buffer, *buffer_remaining, format, args);
62 	if (len >= *buffer_remaining) {
63 		*buffer += *buffer_remaining;
64 		*total += *buffer_remaining;
65 		*buffer_remaining = 0;
66 		LOGERR("bytes remaining is too small!\n");
67 		return -1;
68 	}
69 	*buffer_remaining -= len;
70 	*buffer += len;
71 	*total += len;
72 	return len;
73 }
74 EXPORT_SYMBOL_GPL(uisutil_add_proc_line_ex);
75 
76 int
uisctrl_register_req_handler(int type,void * fptr,ULTRA_VBUS_DEVICEINFO * chipset_driver_info)77 uisctrl_register_req_handler(int type, void *fptr,
78 			     ULTRA_VBUS_DEVICEINFO *chipset_driver_info)
79 {
80 	LOGINF("type = %d, fptr = 0x%p.\n", type, fptr);
81 
82 	switch (type) {
83 	case 2:
84 		if (fptr) {
85 			if (!VirtControlChanFunc)
86 				atomic_inc(&UisUtils_Registered_Services);
87 			VirtControlChanFunc = fptr;
88 		} else {
89 			if (VirtControlChanFunc)
90 				atomic_dec(&UisUtils_Registered_Services);
91 			VirtControlChanFunc = NULL;
92 		}
93 		break;
94 
95 	default:
96 		LOGERR("invalid type %d.\n", type);
97 		return 0;
98 	}
99 	if (chipset_driver_info)
100 		bus_device_info_init(chipset_driver_info, "chipset", "uislib",
101 				   VERSION, NULL);
102 
103 	return 1;
104 }
105 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler);
106 
107 int
uisctrl_register_req_handler_ex(uuid_le switchTypeGuid,const char * switch_type_name,int (* controlfunc)(struct io_msgs *),unsigned long min_channel_bytes,int (* Server_Channel_Ok)(unsigned long channelBytes),int (* Server_Channel_Init)(void * x,unsigned char * clientStr,u32 clientStrLen,u64 bytes),ULTRA_VBUS_DEVICEINFO * chipset_DriverInfo)108 uisctrl_register_req_handler_ex(uuid_le switchTypeGuid,
109 				const char *switch_type_name,
110 				int (*controlfunc)(struct io_msgs *),
111 				unsigned long min_channel_bytes,
112 				int (*Server_Channel_Ok)(unsigned long
113 							  channelBytes),
114 				int (*Server_Channel_Init)
115 				 (void *x, unsigned char *clientStr,
116 				  u32 clientStrLen, u64 bytes),
117 				ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo)
118 {
119 	ReqHandlerInfo_t *pReqHandlerInfo;
120 	int rc = 0;		/* assume failure */
121 
122 	LOGINF("type=%pUL, controlfunc=0x%p.\n",
123 	       &switchTypeGuid, controlfunc);
124 	if (!controlfunc) {
125 		LOGERR("%pUL: controlfunc must be supplied\n", &switchTypeGuid);
126 		goto Away;
127 	}
128 	if (!Server_Channel_Ok) {
129 		LOGERR("%pUL: Server_Channel_Ok must be supplied\n",
130 				&switchTypeGuid);
131 		goto Away;
132 	}
133 	if (!Server_Channel_Init) {
134 		LOGERR("%pUL: Server_Channel_Init must be supplied\n",
135 				&switchTypeGuid);
136 		goto Away;
137 	}
138 	pReqHandlerInfo = ReqHandlerAdd(switchTypeGuid,
139 					switch_type_name,
140 					controlfunc,
141 					min_channel_bytes,
142 					Server_Channel_Ok, Server_Channel_Init);
143 	if (!pReqHandlerInfo) {
144 		LOGERR("failed to add %pUL to server list\n", &switchTypeGuid);
145 		goto Away;
146 	}
147 
148 	atomic_inc(&UisUtils_Registered_Services);
149 	rc = 1;			/* success */
150 Away:
151 	if (rc) {
152 		if (chipset_DriverInfo)
153 			bus_device_info_init(chipset_DriverInfo, "chipset",
154 					   "uislib", VERSION, NULL);
155 	} else
156 		LOGERR("failed to register type %pUL.\n", &switchTypeGuid);
157 
158 	return rc;
159 }
160 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex);
161 
162 int
uisctrl_unregister_req_handler_ex(uuid_le switchTypeGuid)163 uisctrl_unregister_req_handler_ex(uuid_le switchTypeGuid)
164 {
165 	int rc = 0;		/* assume failure */
166 
167 	LOGINF("type=%pUL.\n", &switchTypeGuid);
168 	if (ReqHandlerDel(switchTypeGuid) < 0) {
169 		LOGERR("failed to remove %pUL from server list\n",
170 				&switchTypeGuid);
171 		goto Away;
172 	}
173 	atomic_dec(&UisUtils_Registered_Services);
174 	rc = 1;			/* success */
175 Away:
176 	if (!rc)
177 		LOGERR("failed to unregister type %pUL.\n", &switchTypeGuid);
178 	return rc;
179 }
180 EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex);
181 
182 /*
183  * unsigned int uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
184  *					     void *skb_in,
185  *					     unsigned int firstfraglen,
186  *					     unsigned int frags_max,
187  *					     struct phys_info frags[])
188  *
189  *	calling_ctx - input -   a string that is displayed to show
190  *				who called * this func
191  *	void *skb_in -  skb whose frag info we're copying type is hidden so we
192  *			don't need to include skbbuff in uisutils.h which is
193  *			included in non-networking code.
194  *	unsigned int firstfraglen - input - length of first fragment in skb
195  *	unsigned int frags_max - input - max len of frags array
196  *	struct phys_info frags[] - output - frags array filled in on output
197  *					    return value indicates number of
198  *					    entries filled in frags
199  */
200 unsigned int
uisutil_copy_fragsinfo_from_skb(unsigned char * calling_ctx,void * skb_in,unsigned int firstfraglen,unsigned int frags_max,struct phys_info frags[])201 uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in,
202 				unsigned int firstfraglen,
203 				unsigned int frags_max,
204 				struct phys_info frags[])
205 {
206 	unsigned int count = 0, ii, size, offset = 0, numfrags;
207 	struct sk_buff *skb = skb_in;
208 
209 	numfrags = skb_shinfo(skb)->nr_frags;
210 
211 	while (firstfraglen) {
212 		if (count == frags_max) {
213 			LOGERR("%s frags array too small: max:%d count:%d\n",
214 			       calling_ctx, frags_max, count);
215 			return -1;	/* failure */
216 		}
217 		frags[count].pi_pfn =
218 		    page_to_pfn(virt_to_page(skb->data + offset));
219 		frags[count].pi_off =
220 		    (unsigned long) (skb->data + offset) & PI_PAGE_MASK;
221 		size =
222 		    min(firstfraglen,
223 			(unsigned int) (PI_PAGE_SIZE - frags[count].pi_off));
224 		/* can take smallest of firstfraglen(what's left) OR
225 		* bytes left in the page
226 		*/
227 		frags[count].pi_len = size;
228 		firstfraglen -= size;
229 		offset += size;
230 		count++;
231 	}
232 	if (!numfrags)
233 		goto dolist;
234 
235 	if ((count + numfrags) > frags_max) {
236 		LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n",
237 		     calling_ctx, frags_max, count + numfrags);
238 		return -1;	/* failure */
239 	}
240 
241 	for (ii = 0; ii < numfrags; ii++) {
242 		count = add_physinfo_entries(page_to_pfn(
243 				skb_frag_page(&skb_shinfo(skb)->frags[ii])),
244 					skb_shinfo(skb)->frags[ii].
245 					page_offset,
246 					skb_shinfo(skb)->frags[ii].
247 					size, count, frags_max,
248 					frags);
249 		if (count == 0) {
250 			LOGERR("**** FAILED to add physinfo entries\n");
251 			return -1;	/* failure */
252 		}
253 	}
254 
255 dolist: if (skb_shinfo(skb)->frag_list) {
256 		struct sk_buff *skbinlist;
257 		int c;
258 
259 		for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist;
260 		     skbinlist = skbinlist->next) {
261 
262 			c = uisutil_copy_fragsinfo_from_skb("recursive",
263 				skbinlist,
264 				skbinlist->len - skbinlist->data_len,
265 				frags_max - count,
266 				&frags[count]);
267 			if (c == -1) {
268 				LOGERR("**** FAILED recursive call failed\n");
269 				return -1;
270 			}
271 			count += c;
272 		}
273 	}
274 	return count;
275 }
276 EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb);
277 
278 static LIST_HEAD(ReqHandlerInfo_list);	/* list of ReqHandlerInfo_t */
279 static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock);
280 
281 ReqHandlerInfo_t *
ReqHandlerAdd(uuid_le switchTypeGuid,const char * switch_type_name,int (* controlfunc)(struct io_msgs *),unsigned long min_channel_bytes,int (* Server_Channel_Ok)(unsigned long channelBytes),int (* Server_Channel_Init)(void * x,unsigned char * clientStr,u32 clientStrLen,u64 bytes))282 ReqHandlerAdd(uuid_le switchTypeGuid,
283 	      const char *switch_type_name,
284 	      int (*controlfunc)(struct io_msgs *),
285 	      unsigned long min_channel_bytes,
286 	      int (*Server_Channel_Ok)(unsigned long channelBytes),
287 	      int (*Server_Channel_Init)
288 	       (void *x, unsigned char *clientStr, u32 clientStrLen, u64 bytes))
289 {
290 	ReqHandlerInfo_t *rc = NULL;
291 
292 	rc = kzalloc(sizeof(*rc), GFP_ATOMIC);
293 	if (!rc)
294 		return NULL;
295 	rc->switchTypeGuid = switchTypeGuid;
296 	rc->controlfunc = controlfunc;
297 	rc->min_channel_bytes = min_channel_bytes;
298 	rc->Server_Channel_Ok = Server_Channel_Ok;
299 	rc->Server_Channel_Init = Server_Channel_Init;
300 	if (switch_type_name)
301 		strncpy(rc->switch_type_name, switch_type_name,
302 			sizeof(rc->switch_type_name) - 1);
303 	spin_lock(&ReqHandlerInfo_list_lock);
304 	list_add_tail(&(rc->list_link), &ReqHandlerInfo_list);
305 	spin_unlock(&ReqHandlerInfo_list_lock);
306 
307 	return rc;
308 }
309 
310 ReqHandlerInfo_t *
ReqHandlerFind(uuid_le switchTypeGuid)311 ReqHandlerFind(uuid_le switchTypeGuid)
312 {
313 	struct list_head *lelt, *tmp;
314 	ReqHandlerInfo_t *entry = NULL;
315 
316 	spin_lock(&ReqHandlerInfo_list_lock);
317 	list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
318 		entry = list_entry(lelt, ReqHandlerInfo_t, list_link);
319 		if (uuid_le_cmp(entry->switchTypeGuid, switchTypeGuid) == 0) {
320 			spin_unlock(&ReqHandlerInfo_list_lock);
321 			return entry;
322 		}
323 	}
324 	spin_unlock(&ReqHandlerInfo_list_lock);
325 	return NULL;
326 }
327 
328 int
ReqHandlerDel(uuid_le switchTypeGuid)329 ReqHandlerDel(uuid_le switchTypeGuid)
330 {
331 	struct list_head *lelt, *tmp;
332 	ReqHandlerInfo_t *entry = NULL;
333 	int rc = -1;
334 
335 	spin_lock(&ReqHandlerInfo_list_lock);
336 	list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
337 		entry = list_entry(lelt, ReqHandlerInfo_t, list_link);
338 		if (uuid_le_cmp(entry->switchTypeGuid, switchTypeGuid) == 0) {
339 			list_del(lelt);
340 			kfree(entry);
341 			rc++;
342 		}
343 	}
344 	spin_unlock(&ReqHandlerInfo_list_lock);
345 	return rc;
346 }
347