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