uisutils.c revision 836bee9eee6d13cb4f3bf2a53133fab576877dac
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 <linux/uuid.h> 28#include <linux/skbuff.h> 29#include <linux/uuid.h> 30#ifdef CONFIG_HIGHMEM 31#include <linux/highmem.h> 32#endif 33 34/* this is shorter than using __FILE__ (full path name) in 35 * debug/info/error messages 36 */ 37#define CURRENT_FILE_PC UISLIB_PC_uisutils_c 38#define __MYFILE__ "uisutils.c" 39 40/* exports */ 41atomic_t UisUtils_Registered_Services = ATOMIC_INIT(0); 42 /* num registrations via 43 * uisctrl_register_req_handler() or 44 * uisctrl_register_req_handler_ex() */ 45 46 47/*****************************************************/ 48/* Utility functions */ 49/*****************************************************/ 50 51int 52uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining, 53 char *format, ...) 54{ 55 va_list args; 56 int len; 57 58 DBGINF("buffer = 0x%p : *buffer = 0x%p.\n", buffer, *buffer); 59 va_start(args, format); 60 len = vsnprintf(*buffer, *buffer_remaining, format, args); 61 if (len >= *buffer_remaining) { 62 *buffer += *buffer_remaining; 63 *total += *buffer_remaining; 64 *buffer_remaining = 0; 65 LOGERR("bytes remaining is too small!\n"); 66 return -1; 67 } 68 *buffer_remaining -= len; 69 *buffer += len; 70 *total += len; 71 return len; 72} 73EXPORT_SYMBOL_GPL(uisutil_add_proc_line_ex); 74 75int 76uisctrl_register_req_handler(int type, void *fptr, 77 ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo) 78{ 79 LOGINF("type = %d, fptr = 0x%p.\n", type, fptr); 80 81 switch (type) { 82 case 2: 83 if (fptr) { 84 if (!VirtControlChanFunc) 85 atomic_inc(&UisUtils_Registered_Services); 86 VirtControlChanFunc = fptr; 87 } else { 88 if (VirtControlChanFunc) 89 atomic_dec(&UisUtils_Registered_Services); 90 VirtControlChanFunc = NULL; 91 } 92 break; 93 94 default: 95 LOGERR("invalid type %d.\n", type); 96 return 0; 97 } 98 if (chipset_DriverInfo) 99 BusDeviceInfo_Init(chipset_DriverInfo, "chipset", "uislib", 100 VERSION, NULL); 101 102 return 1; 103} 104EXPORT_SYMBOL_GPL(uisctrl_register_req_handler); 105 106int 107uisctrl_register_req_handler_ex(uuid_le 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 ReqHandlerInfo_t *pReqHandlerInfo; 119 int rc = 0; /* assume failure */ 120 LOGINF("type=%pUL, controlfunc=0x%p.\n", 121 &switchTypeGuid, controlfunc); 122 if (!controlfunc) { 123 LOGERR("%pUL: controlfunc must be supplied\n", &switchTypeGuid); 124 goto Away; 125 } 126 if (!Server_Channel_Ok) { 127 LOGERR("%pUL: Server_Channel_Ok must be supplied\n", 128 &switchTypeGuid); 129 goto Away; 130 } 131 if (!Server_Channel_Init) { 132 LOGERR("%pUL: Server_Channel_Init must be supplied\n", 133 &switchTypeGuid); 134 goto Away; 135 } 136 pReqHandlerInfo = ReqHandlerAdd(switchTypeGuid, 137 switch_type_name, 138 controlfunc, 139 min_channel_bytes, 140 Server_Channel_Ok, Server_Channel_Init); 141 if (!pReqHandlerInfo) { 142 LOGERR("failed to add %pUL to server list\n", &switchTypeGuid); 143 goto Away; 144 } 145 146 atomic_inc(&UisUtils_Registered_Services); 147 rc = 1; /* success */ 148Away: 149 if (rc) { 150 if (chipset_DriverInfo) 151 BusDeviceInfo_Init(chipset_DriverInfo, "chipset", 152 "uislib", VERSION, NULL); 153 } else 154 LOGERR("failed to register type %pUL.\n", &switchTypeGuid); 155 156 return rc; 157} 158EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex); 159 160int 161uisctrl_unregister_req_handler_ex(uuid_le switchTypeGuid) 162{ 163 int rc = 0; /* assume failure */ 164 LOGINF("type=%pUL.\n", &switchTypeGuid); 165 if (ReqHandlerDel(switchTypeGuid) < 0) { 166 LOGERR("failed to remove %pUL from server list\n", 167 &switchTypeGuid); 168 goto Away; 169 } 170 atomic_dec(&UisUtils_Registered_Services); 171 rc = 1; /* success */ 172Away: 173 if (!rc) 174 LOGERR("failed to unregister type %pUL.\n", &switchTypeGuid); 175 return rc; 176} 177EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex); 178 179/* 180 * unsigned int uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx, 181 * void *skb_in, 182 * unsigned int firstfraglen, 183 * unsigned int frags_max, 184 * struct phys_info frags[]) 185 * 186 * calling_ctx - input - a string that is displayed to show 187 * who called * this func 188 * void *skb_in - skb whose frag info we're copying type is hidden so we 189 * don't need to include skbbuff in uisutils.h which is 190 * included in non-networking code. 191 * unsigned int firstfraglen - input - length of first fragment in skb 192 * unsigned int frags_max - input - max len of frags array 193 * struct phys_info frags[] - output - frags array filled in on output 194 * return value indicates number of 195 * entries filled in frags 196 */ 197unsigned int 198uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in, 199 unsigned int firstfraglen, 200 unsigned int frags_max, 201 struct phys_info frags[]) 202{ 203 unsigned int count = 0, ii, size, offset = 0, numfrags; 204 struct sk_buff *skb = skb_in; 205 206 numfrags = skb_shinfo(skb)->nr_frags; 207 208 while (firstfraglen) { 209 if (count == frags_max) { 210 LOGERR("%s frags array too small: max:%d count:%d\n", 211 calling_ctx, frags_max, count); 212 return -1; /* failure */ 213 } 214 frags[count].pi_pfn = 215 page_to_pfn(virt_to_page(skb->data + offset)); 216 frags[count].pi_off = 217 (unsigned long) (skb->data + offset) & PI_PAGE_MASK; 218 size = 219 min(firstfraglen, 220 (unsigned int) (PI_PAGE_SIZE - frags[count].pi_off)); 221 /* can take smallest of firstfraglen(what's left) OR 222 * bytes left in the page 223 */ 224 frags[count].pi_len = size; 225 firstfraglen -= size; 226 offset += size; 227 count++; 228 } 229 if (numfrags) { 230 if ((count + numfrags) > frags_max) { 231 LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n", 232 calling_ctx, frags_max, count + numfrags); 233 return -1; /* failure */ 234 } 235 236 for (ii = 0; ii < numfrags; ii++) { 237 count = add_physinfo_entries(page_to_pfn(skb_frag_page(&skb_shinfo(skb)->frags[ii])), /* pfn */ 238 skb_shinfo(skb)->frags[ii]. 239 page_offset, 240 skb_shinfo(skb)->frags[ii]. 241 size, count, frags_max, 242 frags); 243 if (count == 0) { 244 LOGERR("**** FAILED to add physinfo entries\n"); 245 return -1; /* failure */ 246 } 247 } 248 } 249 if (skb_shinfo(skb)->frag_list) { 250 struct sk_buff *skbinlist; 251 int c; 252 for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist; 253 skbinlist = skbinlist->next) { 254 255 c = uisutil_copy_fragsinfo_from_skb("recursive", 256 skbinlist, 257 skbinlist->len - 258 skbinlist->data_len, 259 frags_max - count, 260 &frags[count]); 261 if (c == -1) { 262 LOGERR("**** FAILED recursive call failed\n"); 263 return -1; 264 } 265 count += c; 266 } 267 } 268 return count; 269} 270EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb); 271 272static LIST_HEAD(ReqHandlerInfo_list); /* list of ReqHandlerInfo_t */ 273static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock); 274 275ReqHandlerInfo_t * 276ReqHandlerAdd(uuid_le switchTypeGuid, 277 const char *switch_type_name, 278 int (*controlfunc)(struct io_msgs *), 279 unsigned long min_channel_bytes, 280 int (*Server_Channel_Ok)(unsigned long channelBytes), 281 int (*Server_Channel_Init) 282 (void *x, unsigned char *clientStr, U32 clientStrLen, U64 bytes)) 283{ 284 ReqHandlerInfo_t *rc = NULL; 285 286 rc = kzalloc(sizeof(*rc), GFP_ATOMIC); 287 if (!rc) 288 return NULL; 289 rc->switchTypeGuid = switchTypeGuid; 290 rc->controlfunc = controlfunc; 291 rc->min_channel_bytes = min_channel_bytes; 292 rc->Server_Channel_Ok = Server_Channel_Ok; 293 rc->Server_Channel_Init = Server_Channel_Init; 294 if (switch_type_name) 295 strncpy(rc->switch_type_name, switch_type_name, 296 sizeof(rc->switch_type_name) - 1); 297 spin_lock(&ReqHandlerInfo_list_lock); 298 list_add_tail(&(rc->list_link), &ReqHandlerInfo_list); 299 spin_unlock(&ReqHandlerInfo_list_lock); 300 301 return rc; 302} 303 304ReqHandlerInfo_t * 305ReqHandlerFind(uuid_le switchTypeGuid) 306{ 307 struct list_head *lelt, *tmp; 308 ReqHandlerInfo_t *entry = NULL; 309 spin_lock(&ReqHandlerInfo_list_lock); 310 list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) { 311 entry = list_entry(lelt, ReqHandlerInfo_t, list_link); 312 if (uuid_le_cmp(entry->switchTypeGuid, switchTypeGuid) == 0) { 313 spin_unlock(&ReqHandlerInfo_list_lock); 314 return entry; 315 } 316 } 317 spin_unlock(&ReqHandlerInfo_list_lock); 318 return NULL; 319} 320 321int 322ReqHandlerDel(uuid_le switchTypeGuid) 323{ 324 struct list_head *lelt, *tmp; 325 ReqHandlerInfo_t *entry = NULL; 326 int rc = -1; 327 spin_lock(&ReqHandlerInfo_list_lock); 328 list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) { 329 entry = list_entry(lelt, ReqHandlerInfo_t, list_link); 330 if (uuid_le_cmp(entry->switchTypeGuid, switchTypeGuid) == 0) { 331 list_del(lelt); 332 kfree(entry); 333 rc++; 334 } 335 } 336 spin_unlock(&ReqHandlerInfo_list_lock); 337 return rc; 338} 339