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