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
);
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");
67 *buffer_remaining
-= len
;
72 EXPORT_SYMBOL_GPL(uisutil_add_proc_line_ex
);
75 uisctrl_register_req_handler(int type
, void *fptr
,
76 struct ultra_vbus_deviceinfo
*chipset_driver_info
)
78 LOGINF("type = %d, fptr = 0x%p.\n", type
, fptr
);
83 if (!virt_control_chan_func
)
84 atomic_inc(&uisutils_registered_services
);
85 virt_control_chan_func
= fptr
;
87 if (virt_control_chan_func
)
88 atomic_dec(&uisutils_registered_services
);
89 virt_control_chan_func
= NULL
;
94 LOGERR("invalid type %d.\n", type
);
97 if (chipset_driver_info
)
98 bus_device_info_init(chipset_driver_info
, "chipset", "uislib",
103 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler
);
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
)
116 struct req_handler_info
*req_handler
;
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 req_handler
= req_handler_add(switch_uuid
,
138 server_channel_ok
, server_channel_init
);
140 LOGERR("failed to add %pUL to server list\n", &switch_uuid
);
144 atomic_inc(&uisutils_registered_services
);
145 if (chipset_driver_info
) {
146 bus_device_info_init(chipset_driver_info
, "chipset",
147 "uislib", VERSION
, NULL
);
151 LOGERR("failed to register type %pUL.\n", &switch_uuid
);
154 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex
);
157 uisctrl_unregister_req_handler_ex(uuid_le switch_uuid
)
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",
165 atomic_dec(&uisutils_registered_services
);
168 EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex
);
171 * unsigned int uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
173 * unsigned int firstfraglen,
174 * unsigned int frags_max,
175 * struct phys_info frags[])
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
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
[])
194 unsigned int count
= 0, ii
, size
, offset
= 0, numfrags
;
195 struct sk_buff
*skb
= skb_in
;
197 numfrags
= skb_shinfo(skb
)->nr_frags
;
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 */
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
;
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
215 frags
[count
].pi_len
= size
;
216 firstfraglen
-= size
;
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 */
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
].
234 skb_shinfo(skb
)->frags
[ii
].
235 size
, count
, frags_max
,
238 LOGERR("**** FAILED to add physinfo entries\n");
239 return -1; /* failure */
243 dolist
: if (skb_shinfo(skb
)->frag_list
) {
244 struct sk_buff
*skbinlist
;
247 for (skbinlist
= skb_shinfo(skb
)->frag_list
; skbinlist
;
248 skbinlist
= skbinlist
->next
) {
249 c
= uisutil_copy_fragsinfo_from_skb("recursive",
251 skbinlist
->len
- skbinlist
->data_len
,
255 LOGERR("**** FAILED recursive call failed\n");
263 EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb
);
265 static LIST_HEAD(req_handler_info_list
); /* list of struct req_handler_info */
266 static DEFINE_SPINLOCK(req_handler_info_list_lock
);
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
,
278 struct req_handler_info
*rc
= NULL
;
280 rc
= kzalloc(sizeof(*rc
), GFP_ATOMIC
);
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
);
298 struct req_handler_info
*
299 req_handler_find(uuid_le switch_uuid
)
301 struct list_head
*lelt
, *tmp
;
302 struct req_handler_info
*entry
= NULL
;
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
);
312 spin_unlock(&req_handler_info_list_lock
);
317 req_handler_del(uuid_le switch_uuid
)
319 struct list_head
*lelt
, *tmp
;
320 struct req_handler_info
*entry
= NULL
;
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) {
332 spin_unlock(&req_handler_info_list_lock
);