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