3 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
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.
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
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>
27 #include "vbushelper.h"
28 #include <linux/skbuff.h>
30 #include <linux/highmem.h>
33 /* this is shorter than using __FILE__ (full path name) in
34 * debug/info/error messages
36 #define CURRENT_FILE_PC UISLIB_PC_uisutils_c
37 #define __MYFILE__ "uisutils.c"
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() */
45 /*****************************************************/
46 /* Utility functions */
47 /*****************************************************/
50 uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
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 if (len >= *buffer_remaining) {
60 *buffer += *buffer_remaining;
61 *total += *buffer_remaining;
62 *buffer_remaining = 0;
63 LOGERR("bytes remaining is too small!\n");
66 *buffer_remaining -= len;
71 EXPORT_SYMBOL_GPL(uisutil_add_proc_line_ex);
74 uisctrl_register_req_handler(int type, void *fptr,
75 struct ultra_vbus_deviceinfo *chipset_driver_info)
77 LOGINF("type = %d, fptr = 0x%p.\n", type, fptr);
82 if (!virt_control_chan_func)
83 atomic_inc(&uisutils_registered_services);
84 virt_control_chan_func = fptr;
86 if (virt_control_chan_func)
87 atomic_dec(&uisutils_registered_services);
88 virt_control_chan_func = NULL;
93 LOGERR("invalid type %d.\n", type);
96 if (chipset_driver_info)
97 bus_device_info_init(chipset_driver_info, "chipset", "uislib",
102 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler);
105 uisctrl_register_req_handler_ex(uuid_le switch_uuid,
106 const char *switch_type_name,
107 int (*controlfunc)(struct io_msgs *),
108 unsigned long min_channel_bytes,
109 int (*server_channel_ok)(unsigned long channel_bytes),
110 int (*server_channel_init)(void *x,
111 unsigned char *client_str,
112 u32 client_str_len, u64 bytes),
113 struct ultra_vbus_deviceinfo *chipset_driver_info)
115 struct req_handler_info *pReqHandlerInfo;
116 int rc = 0; /* assume failure */
118 LOGINF("type=%pUL, controlfunc=0x%p.\n",
119 &switch_uuid, controlfunc);
121 LOGERR("%pUL: controlfunc must be supplied\n", &switch_uuid);
124 if (!server_channel_ok) {
125 LOGERR("%pUL: Server_Channel_Ok must be supplied\n",
129 if (!server_channel_init) {
130 LOGERR("%pUL: Server_Channel_Init must be supplied\n",
134 pReqHandlerInfo = req_handler_add(switch_uuid,
138 server_channel_ok, server_channel_init);
139 if (!pReqHandlerInfo) {
140 LOGERR("failed to add %pUL to server list\n", &switch_uuid);
144 atomic_inc(&uisutils_registered_services);
145 rc = 1; /* success */
148 if (chipset_driver_info)
149 bus_device_info_init(chipset_driver_info, "chipset",
150 "uislib", VERSION, NULL);
152 LOGERR("failed to register type %pUL.\n", &switch_uuid);
156 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex);
159 uisctrl_unregister_req_handler_ex(uuid_le switch_uuid)
161 int rc = 0; /* assume failure */
163 LOGINF("type=%pUL.\n", &switch_uuid);
164 if (req_handler_del(switch_uuid) < 0) {
165 LOGERR("failed to remove %pUL from server list\n",
169 atomic_dec(&uisutils_registered_services);
170 rc = 1; /* success */
173 LOGERR("failed to unregister type %pUL.\n", &switch_uuid);
176 EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex);
179 * unsigned int uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
181 * unsigned int firstfraglen,
182 * unsigned int frags_max,
183 * struct phys_info frags[])
185 * calling_ctx - input - a string that is displayed to show
186 * who called * this func
187 * void *skb_in - skb whose frag info we're copying type is hidden so we
188 * don't need to include skbbuff in uisutils.h which is
189 * included in non-networking code.
190 * unsigned int firstfraglen - input - length of first fragment in skb
191 * unsigned int frags_max - input - max len of frags array
192 * struct phys_info frags[] - output - frags array filled in on output
193 * return value indicates number of
194 * entries filled in frags
197 uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in,
198 unsigned int firstfraglen,
199 unsigned int frags_max,
200 struct phys_info frags[])
202 unsigned int count = 0, ii, size, offset = 0, numfrags;
203 struct sk_buff *skb = skb_in;
205 numfrags = skb_shinfo(skb)->nr_frags;
207 while (firstfraglen) {
208 if (count == frags_max) {
209 LOGERR("%s frags array too small: max:%d count:%d\n",
210 calling_ctx, frags_max, count);
211 return -1; /* failure */
213 frags[count].pi_pfn =
214 page_to_pfn(virt_to_page(skb->data + offset));
215 frags[count].pi_off =
216 (unsigned long) (skb->data + offset) & PI_PAGE_MASK;
219 (unsigned int) (PI_PAGE_SIZE - frags[count].pi_off));
220 /* can take smallest of firstfraglen(what's left) OR
221 * bytes left in the page
223 frags[count].pi_len = size;
224 firstfraglen -= size;
231 if ((count + numfrags) > frags_max) {
232 LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n",
233 calling_ctx, frags_max, count + numfrags);
234 return -1; /* failure */
237 for (ii = 0; ii < numfrags; ii++) {
238 count = add_physinfo_entries(page_to_pfn(
239 skb_frag_page(&skb_shinfo(skb)->frags[ii])),
240 skb_shinfo(skb)->frags[ii].
242 skb_shinfo(skb)->frags[ii].
243 size, count, frags_max,
246 LOGERR("**** FAILED to add physinfo entries\n");
247 return -1; /* failure */
251 dolist: if (skb_shinfo(skb)->frag_list) {
252 struct sk_buff *skbinlist;
255 for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist;
256 skbinlist = skbinlist->next) {
257 c = uisutil_copy_fragsinfo_from_skb("recursive",
259 skbinlist->len - skbinlist->data_len,
263 LOGERR("**** FAILED recursive call failed\n");
271 EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb);
273 static LIST_HEAD(ReqHandlerInfo_list); /* list of struct req_handler_info */
274 static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock);
276 struct req_handler_info *
277 req_handler_add(uuid_le switch_uuid,
278 const char *switch_type_name,
279 int (*controlfunc)(struct io_msgs *),
280 unsigned long min_channel_bytes,
281 int (*Server_Channel_Ok)(unsigned long channelBytes),
282 int (*Server_Channel_Init)
283 (void *x, unsigned char *clientStr, u32 clientStrLen, u64 bytes))
285 struct req_handler_info *rc = NULL;
287 rc = kzalloc(sizeof(*rc), GFP_ATOMIC);
290 rc->switch_uuid = switch_uuid;
291 rc->controlfunc = controlfunc;
292 rc->min_channel_bytes = min_channel_bytes;
293 rc->server_channel_ok = Server_Channel_Ok;
294 rc->server_channel_init = Server_Channel_Init;
295 if (switch_type_name)
296 strncpy(rc->switch_type_name, switch_type_name,
297 sizeof(rc->switch_type_name) - 1);
298 spin_lock(&ReqHandlerInfo_list_lock);
299 list_add_tail(&(rc->list_link), &ReqHandlerInfo_list);
300 spin_unlock(&ReqHandlerInfo_list_lock);
305 struct req_handler_info *
306 req_handler_find(uuid_le switch_uuid)
308 struct list_head *lelt, *tmp;
309 struct req_handler_info *entry = NULL;
311 spin_lock(&ReqHandlerInfo_list_lock);
312 list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
313 entry = list_entry(lelt, struct req_handler_info, list_link);
314 if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
315 spin_unlock(&ReqHandlerInfo_list_lock);
319 spin_unlock(&ReqHandlerInfo_list_lock);
324 req_handler_del(uuid_le switch_uuid)
326 struct list_head *lelt, *tmp;
327 struct req_handler_info *entry = NULL;
330 spin_lock(&ReqHandlerInfo_list_lock);
331 list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
332 entry = list_entry(lelt, struct req_handler_info, list_link);
333 if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
339 spin_unlock(&ReqHandlerInfo_list_lock);