uisutils.c revision 29a9e89548408028498bb63bcaabe2806232e26a
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 */ 42atomic_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 52int 53uisutil_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} 74EXPORT_SYMBOL_GPL(uisutil_add_proc_line_ex); 75 76int 77uisctrl_register_req_handler(int type, void *fptr, 78 ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo) 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_DriverInfo) 100 BusDeviceInfo_Init(chipset_DriverInfo, "chipset", "uislib", 101 VERSION, NULL); 102 103 return 1; 104} 105EXPORT_SYMBOL_GPL(uisctrl_register_req_handler); 106 107int 108uisctrl_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 */ 150Away: 151 if (rc) { 152 if (chipset_DriverInfo) 153 BusDeviceInfo_Init(chipset_DriverInfo, "chipset", 154 "uislib", VERSION, NULL); 155 } else 156 LOGERR("failed to register type %pUL.\n", &switchTypeGuid); 157 158 return rc; 159} 160EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex); 161 162int 163uisctrl_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 */ 175Away: 176 if (!rc) 177 LOGERR("failed to unregister type %pUL.\n", &switchTypeGuid); 178 return rc; 179} 180EXPORT_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 */ 200unsigned int 201uisutil_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 255dolist: 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} 276EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb); 277 278static LIST_HEAD(ReqHandlerInfo_list); /* list of ReqHandlerInfo_t */ 279static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock); 280 281ReqHandlerInfo_t * 282ReqHandlerAdd(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 310ReqHandlerInfo_t * 311ReqHandlerFind(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 328int 329ReqHandlerDel(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