uisutils.c revision 1566ac0bc919187bb605403f072fd3ebc58b00a0
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 if ((count + numfrags) > frags_max) { 234 LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n", 235 calling_ctx, frags_max, count + numfrags); 236 return -1; /* failure */ 237 } 238 239 for (ii = 0; ii < numfrags; ii++) { 240 count = add_physinfo_entries(page_to_pfn(skb_frag_page(&skb_shinfo(skb)->frags[ii])), /* pfn */ 241 skb_shinfo(skb)->frags[ii]. 242 page_offset, 243 skb_shinfo(skb)->frags[ii]. 244 size, count, frags_max, 245 frags); 246 if (count == 0) { 247 LOGERR("**** FAILED to add physinfo entries\n"); 248 return -1; /* failure */ 249 } 250 } 251 } 252 if (skb_shinfo(skb)->frag_list) { 253 struct sk_buff *skbinlist; 254 int c; 255 256 for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist; 257 skbinlist = skbinlist->next) { 258 259 c = uisutil_copy_fragsinfo_from_skb("recursive", 260 skbinlist, 261 skbinlist->len - 262 skbinlist->data_len, 263 frags_max - count, 264 &frags[count]); 265 if (c == -1) { 266 LOGERR("**** FAILED recursive call failed\n"); 267 return -1; 268 } 269 count += c; 270 } 271 } 272 return count; 273} 274EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb); 275 276static LIST_HEAD(ReqHandlerInfo_list); /* list of ReqHandlerInfo_t */ 277static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock); 278 279ReqHandlerInfo_t * 280ReqHandlerAdd(uuid_le switchTypeGuid, 281 const char *switch_type_name, 282 int (*controlfunc)(struct io_msgs *), 283 unsigned long min_channel_bytes, 284 int (*Server_Channel_Ok)(unsigned long channelBytes), 285 int (*Server_Channel_Init) 286 (void *x, unsigned char *clientStr, u32 clientStrLen, u64 bytes)) 287{ 288 ReqHandlerInfo_t *rc = NULL; 289 290 rc = kzalloc(sizeof(*rc), GFP_ATOMIC); 291 if (!rc) 292 return NULL; 293 rc->switchTypeGuid = switchTypeGuid; 294 rc->controlfunc = controlfunc; 295 rc->min_channel_bytes = min_channel_bytes; 296 rc->Server_Channel_Ok = Server_Channel_Ok; 297 rc->Server_Channel_Init = Server_Channel_Init; 298 if (switch_type_name) 299 strncpy(rc->switch_type_name, switch_type_name, 300 sizeof(rc->switch_type_name) - 1); 301 spin_lock(&ReqHandlerInfo_list_lock); 302 list_add_tail(&(rc->list_link), &ReqHandlerInfo_list); 303 spin_unlock(&ReqHandlerInfo_list_lock); 304 305 return rc; 306} 307 308ReqHandlerInfo_t * 309ReqHandlerFind(uuid_le switchTypeGuid) 310{ 311 struct list_head *lelt, *tmp; 312 ReqHandlerInfo_t *entry = NULL; 313 314 spin_lock(&ReqHandlerInfo_list_lock); 315 list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) { 316 entry = list_entry(lelt, ReqHandlerInfo_t, list_link); 317 if (uuid_le_cmp(entry->switchTypeGuid, switchTypeGuid) == 0) { 318 spin_unlock(&ReqHandlerInfo_list_lock); 319 return entry; 320 } 321 } 322 spin_unlock(&ReqHandlerInfo_list_lock); 323 return NULL; 324} 325 326int 327ReqHandlerDel(uuid_le switchTypeGuid) 328{ 329 struct list_head *lelt, *tmp; 330 ReqHandlerInfo_t *entry = NULL; 331 int rc = -1; 332 333 spin_lock(&ReqHandlerInfo_list_lock); 334 list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) { 335 entry = list_entry(lelt, ReqHandlerInfo_t, list_link); 336 if (uuid_le_cmp(entry->switchTypeGuid, switchTypeGuid) == 0) { 337 list_del(lelt); 338 kfree(entry); 339 rc++; 340 } 341 } 342 spin_unlock(&ReqHandlerInfo_list_lock); 343 return rc; 344} 345