mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 23:27:06 +00:00
staging: visoruislib driver used to handle requests from virtpci
The visoruislib module is a support library, used to handle requests from virtpci. Signed-off-by: Ken Cox <jkc@redhat.com> Cc: Ben Romer <sparmaintainer@unisys.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
7b2a2d8383
commit
bac8a4d5d2
9 changed files with 3195 additions and 1 deletions
|
@ -13,5 +13,6 @@ source "drivers/staging/unisys/visorutil/Kconfig"
|
|||
source "drivers/staging/unisys/visorchannel/Kconfig"
|
||||
source "drivers/staging/unisys/visorchipset/Kconfig"
|
||||
source "drivers/staging/unisys/channels/Kconfig"
|
||||
source "drivers/staging/unisys/uislib/Kconfig"
|
||||
|
||||
endif # UNISYSSPAR
|
||||
|
|
|
@ -5,4 +5,4 @@ obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil/
|
|||
obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel/
|
||||
obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset/
|
||||
obj-$(CONFIG_UNISYS_CHANNELSTUB) += channels/
|
||||
|
||||
obj-$(CONFIG_UNISYS_UISLIB) += uislib/
|
||||
|
|
30
drivers/staging/unisys/include/sparstop.h
Normal file
30
drivers/staging/unisys/include/sparstop.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* sparstop.h
|
||||
*
|
||||
* Copyright © 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
#ifndef __SPARSTOP_H__
|
||||
#define __SPARSTOP_H__
|
||||
|
||||
#include "timskmod.h"
|
||||
#include "version.h"
|
||||
#include <linux/ctype.h>
|
||||
|
||||
typedef void (*SPARSTOP_COMPLETE_FUNC) (void *context, int status);
|
||||
|
||||
int sp_stop(void *context, SPARSTOP_COMPLETE_FUNC get_complete_func);
|
||||
void test_remove_stop_device(void);
|
||||
|
||||
#endif
|
10
drivers/staging/unisys/uislib/Kconfig
Normal file
10
drivers/staging/unisys/uislib/Kconfig
Normal file
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# Unisys uislib configuration
|
||||
#
|
||||
|
||||
config UNISYS_UISLIB
|
||||
tristate "Unisys uislib driver"
|
||||
depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB
|
||||
---help---
|
||||
If you say Y here, you will enable the Unisys uislib driver.
|
||||
|
17
drivers/staging/unisys/uislib/Makefile
Normal file
17
drivers/staging/unisys/uislib/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Makefile for Unisys uislib
|
||||
#
|
||||
|
||||
obj-$(CONFIG_UNISYS_UISLIB) += visoruislib.o
|
||||
|
||||
visoruislib-y := uislib.o uisqueue.o uisthread.o uisutils.o
|
||||
|
||||
ccflags-y += -Idrivers/staging/unisys/include
|
||||
ccflags-y += -Idrivers/staging/unisys/channels
|
||||
ccflags-y += -Idrivers/staging/unisys/visorchipset
|
||||
ccflags-y += -Idrivers/staging/unisys/sparstopdriver
|
||||
ccflags-y += -Idrivers/staging/unisys/common-spar/include
|
||||
ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
|
||||
|
||||
ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
|
||||
|
2536
drivers/staging/unisys/uislib/uislib.c
Normal file
2536
drivers/staging/unisys/uislib/uislib.c
Normal file
File diff suppressed because it is too large
Load diff
166
drivers/staging/unisys/uislib/uisqueue.c
Normal file
166
drivers/staging/unisys/uislib/uisqueue.c
Normal file
|
@ -0,0 +1,166 @@
|
|||
/* uisqueue.c
|
||||
*
|
||||
* Copyright © 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/* @ALL_INSPECTED */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "uisutils.h"
|
||||
|
||||
#include "chanstub.h"
|
||||
|
||||
/* this is shorter than using __FILE__ (full path name) in
|
||||
* debug/info/error messages */
|
||||
#define CURRENT_FILE_PC UISLIB_PC_uisqueue_c
|
||||
#define __MYFILE__ "uisqueue.c"
|
||||
|
||||
#define RETVOID do { goto Away; } while (0)
|
||||
#define RETINT(x) do { rc = (x); goto Away; } while (0)
|
||||
#define RETPTR(x) do { rc = (x); goto Away; } while (0)
|
||||
#define RETBOOL(x) do { rc = (x); goto Away; } while (0)
|
||||
|
||||
#define CHECK_CACHE_ALIGN 0
|
||||
|
||||
/*****************************************************/
|
||||
/* Exported functions */
|
||||
/*****************************************************/
|
||||
unsigned long long
|
||||
uisqueue_InterlockedOr(volatile unsigned long long *Target,
|
||||
unsigned long long Set)
|
||||
{
|
||||
unsigned long long i;
|
||||
unsigned long long j;
|
||||
|
||||
j = *Target;
|
||||
do {
|
||||
i = j;
|
||||
j = uislibcmpxchg64((unsigned long long *) Target,
|
||||
i, i | Set, sizeof(*(Target)));
|
||||
|
||||
} while (i != j);
|
||||
|
||||
return j;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uisqueue_InterlockedOr);
|
||||
|
||||
unsigned long long
|
||||
uisqueue_InterlockedAnd(volatile unsigned long long *Target,
|
||||
unsigned long long Set)
|
||||
{
|
||||
unsigned long long i;
|
||||
unsigned long long j;
|
||||
|
||||
j = *Target;
|
||||
do {
|
||||
i = j;
|
||||
j = uislibcmpxchg64((unsigned long long *) Target,
|
||||
i, i & Set, sizeof(*(Target)));
|
||||
|
||||
} while (i != j);
|
||||
|
||||
return j;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uisqueue_InterlockedAnd);
|
||||
|
||||
static U8
|
||||
do_locked_client_insert(struct uisqueue_info *queueinfo,
|
||||
unsigned int whichqueue,
|
||||
void *pSignal,
|
||||
spinlock_t *lock,
|
||||
unsigned char issueInterruptIfEmpty,
|
||||
U64 interruptHandle, U8 *channelId)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char queueWasEmpty;
|
||||
unsigned int locked = 0;
|
||||
unsigned int acquired = 0;
|
||||
U8 rc = 0;
|
||||
|
||||
spin_lock_irqsave(lock, flags);
|
||||
locked = 1;
|
||||
|
||||
if (!ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(queueinfo->chan, channelId, NULL))
|
||||
RETINT(0);
|
||||
|
||||
acquired = 1;
|
||||
|
||||
queueWasEmpty = SignalQueueIsEmpty(queueinfo->chan, whichqueue);
|
||||
if (!SignalInsert(queueinfo->chan, whichqueue, pSignal))
|
||||
RETINT(0);
|
||||
ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId, NULL);
|
||||
acquired = 0;
|
||||
spin_unlock_irqrestore(lock, flags);
|
||||
locked = 0;
|
||||
|
||||
queueinfo->packets_sent++;
|
||||
|
||||
RETINT(1);
|
||||
|
||||
Away:
|
||||
if (acquired) {
|
||||
ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId,
|
||||
NULL);
|
||||
acquired = 0;
|
||||
}
|
||||
if (locked) {
|
||||
spin_unlock_irqrestore((spinlock_t *) lock, flags);
|
||||
locked = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo,
|
||||
struct uiscmdrsp *cmdrsp,
|
||||
unsigned int whichqueue,
|
||||
void *insertlock,
|
||||
unsigned char issueInterruptIfEmpty,
|
||||
U64 interruptHandle,
|
||||
char oktowait, U8 *channelId)
|
||||
{
|
||||
while (!do_locked_client_insert(queueinfo, whichqueue, cmdrsp,
|
||||
(spinlock_t *) insertlock,
|
||||
issueInterruptIfEmpty,
|
||||
interruptHandle, channelId)) {
|
||||
if (oktowait != OK_TO_WAIT) {
|
||||
LOGERR("****FAILED SignalInsert failed; cannot wait; insert aborted\n");
|
||||
return 0; /* failed to queue */
|
||||
}
|
||||
/* try again */
|
||||
LOGERR("****FAILED SignalInsert failed; waiting to try again\n");
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(msecs_to_jiffies(10));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uisqueue_put_cmdrsp_with_lock_client);
|
||||
|
||||
/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue
|
||||
* returns NULL if queue is empty */
|
||||
int
|
||||
uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo,
|
||||
void *cmdrsp, unsigned int whichqueue)
|
||||
{
|
||||
if (!SignalRemove(queueinfo->chan, whichqueue, cmdrsp))
|
||||
return 0;
|
||||
|
||||
queueinfo->packets_received++;
|
||||
|
||||
return 1; /* Success */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uisqueue_get_cmdrsp);
|
85
drivers/staging/unisys/uislib/uisthread.c
Normal file
85
drivers/staging/unisys/uislib/uisthread.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/* uisthread.c
|
||||
*
|
||||
* Copyright © 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/* @ALL_INSPECTED */
|
||||
#include <asm/processor.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kthread.h>
|
||||
#include "uniklog.h"
|
||||
#include "uisutils.h"
|
||||
#include "uisthread.h"
|
||||
|
||||
#define KILL(a, b, c) kill_pid(find_vpid(a), b, c)
|
||||
|
||||
/* this is shorter than using __FILE__ (full path name) in
|
||||
* debug/info/error messages
|
||||
*/
|
||||
#define CURRENT_FILE_PC UISLIB_PC_uisthread_c
|
||||
#define __MYFILE__ "uisthread.c"
|
||||
|
||||
/*****************************************************/
|
||||
/* Exported functions */
|
||||
/*****************************************************/
|
||||
|
||||
/* returns 0 for failure, 1 for success */
|
||||
int
|
||||
uisthread_start(struct uisthread_info *thrinfo,
|
||||
int (*threadfn)(void *), void *thrcontext, char *name)
|
||||
{
|
||||
thrinfo->should_stop = 0;
|
||||
/* used to stop the thread */
|
||||
init_completion(&thrinfo->has_stopped);
|
||||
thrinfo->task = kthread_create(threadfn, thrcontext, name, NULL);
|
||||
if (thrinfo->task == NULL) {
|
||||
thrinfo->id = 0;
|
||||
return 0; /* failure */
|
||||
}
|
||||
thrinfo->id = thrinfo->task->pid;
|
||||
wake_up_process(thrinfo->task);
|
||||
LOGINF("started thread pid:%d\n", thrinfo->id);
|
||||
return 1;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uisthread_start);
|
||||
|
||||
void
|
||||
uisthread_stop(struct uisthread_info *thrinfo)
|
||||
{
|
||||
int ret;
|
||||
int stopped = 0;
|
||||
if (thrinfo->id == 0)
|
||||
return; /* thread not running */
|
||||
|
||||
LOGINF("uisthread_stop stopping id:%d\n", thrinfo->id);
|
||||
thrinfo->should_stop = 1;
|
||||
ret = KILL(thrinfo->id, SIGHUP, 1);
|
||||
if (ret) {
|
||||
LOGERR("unable to signal thread %d\n", ret);
|
||||
} else {
|
||||
/* give up if the thread has NOT died in 1 minute */
|
||||
if (wait_for_completion_timeout(&thrinfo->has_stopped, 60 * HZ))
|
||||
stopped = 1;
|
||||
else
|
||||
LOGERR("timed out trying to signal thread\n");
|
||||
}
|
||||
if (stopped) {
|
||||
LOGINF("uisthread_stop stopped id:%d\n", thrinfo->id);
|
||||
thrinfo->id = 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uisthread_stop);
|
349
drivers/staging/unisys/uislib/uisutils.c
Normal file
349
drivers/staging/unisys/uislib/uisutils.c
Normal file
|
@ -0,0 +1,349 @@
|
|||
/* uisutils.c
|
||||
*
|
||||
* Copyright © 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <commontypes.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include "uniklog.h"
|
||||
#include "uisutils.h"
|
||||
#include "version.h"
|
||||
#include "vbushelper.h"
|
||||
#include "guidutils.h"
|
||||
#include <linux/skbuff.h>
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
#include <linux/highmem.h>
|
||||
#endif
|
||||
|
||||
/* this is shorter than using __FILE__ (full path name) in
|
||||
* debug/info/error messages
|
||||
*/
|
||||
#define CURRENT_FILE_PC UISLIB_PC_uisutils_c
|
||||
#define __MYFILE__ "uisutils.c"
|
||||
|
||||
/* exports */
|
||||
atomic_t UisUtils_Registered_Services = ATOMIC_INIT(0);
|
||||
/* num registrations via
|
||||
* uisctrl_register_req_handler() or
|
||||
* uisctrl_register_req_handler_ex() */
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Utility functions */
|
||||
/*****************************************************/
|
||||
|
||||
int
|
||||
util_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
|
||||
char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int len;
|
||||
|
||||
DBGINF("buffer = 0x%p : *buffer = 0x%p.\n", buffer, *buffer);
|
||||
va_start(args, format);
|
||||
len = vsnprintf(*buffer, *buffer_remaining, format, args);
|
||||
if (len >= *buffer_remaining) {
|
||||
*buffer += *buffer_remaining;
|
||||
*total += *buffer_remaining;
|
||||
*buffer_remaining = 0;
|
||||
LOGERR("bytes remaining is too small!\n");
|
||||
return -1;
|
||||
}
|
||||
*buffer_remaining -= len;
|
||||
*buffer += len;
|
||||
*total += len;
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(util_add_proc_line_ex);
|
||||
|
||||
int
|
||||
uisctrl_register_req_handler(int type, void *fptr,
|
||||
ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo)
|
||||
{
|
||||
LOGINF("type = %d, fptr = 0x%p.\n", type, fptr);
|
||||
|
||||
switch (type) {
|
||||
case 2:
|
||||
if (fptr) {
|
||||
if (!VirtControlChanFunc)
|
||||
atomic_inc(&UisUtils_Registered_Services);
|
||||
VirtControlChanFunc = fptr;
|
||||
} else {
|
||||
if (VirtControlChanFunc)
|
||||
atomic_dec(&UisUtils_Registered_Services);
|
||||
VirtControlChanFunc = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGERR("invalid type %d.\n", type);
|
||||
return 0;
|
||||
}
|
||||
if (chipset_DriverInfo)
|
||||
BusDeviceInfo_Init(chipset_DriverInfo,
|
||||
"chipset", "uislib",
|
||||
VERSION, NULL, __DATE__, __TIME__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uisctrl_register_req_handler);
|
||||
|
||||
int
|
||||
uisctrl_register_req_handler_ex(GUID switchTypeGuid,
|
||||
const char *switch_type_name,
|
||||
int (*controlfunc)(struct io_msgs *),
|
||||
unsigned long min_channel_bytes,
|
||||
int (*Server_Channel_Ok)(unsigned long
|
||||
channelBytes),
|
||||
int (*Server_Channel_Init)
|
||||
(void *x, unsigned char *clientStr,
|
||||
U32 clientStrLen, U64 bytes),
|
||||
ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo)
|
||||
{
|
||||
char s[99];
|
||||
ReqHandlerInfo_t *pReqHandlerInfo;
|
||||
int rc = 0; /* assume failure */
|
||||
LOGINF("type=%s, controlfunc=0x%p.\n",
|
||||
GUID_format1(&switchTypeGuid, s), controlfunc);
|
||||
if (!controlfunc) {
|
||||
LOGERR("%s: controlfunc must be supplied\n",
|
||||
GUID_format1(&switchTypeGuid, s));
|
||||
goto Away;
|
||||
}
|
||||
if (!Server_Channel_Ok) {
|
||||
LOGERR("%s: Server_Channel_Ok must be supplied\n",
|
||||
GUID_format1(&switchTypeGuid, s));
|
||||
goto Away;
|
||||
}
|
||||
if (!Server_Channel_Init) {
|
||||
LOGERR("%s: Server_Channel_Init must be supplied\n",
|
||||
GUID_format1(&switchTypeGuid, s));
|
||||
goto Away;
|
||||
}
|
||||
pReqHandlerInfo = ReqHandlerAdd(switchTypeGuid,
|
||||
switch_type_name,
|
||||
controlfunc,
|
||||
min_channel_bytes,
|
||||
Server_Channel_Ok, Server_Channel_Init);
|
||||
if (!pReqHandlerInfo) {
|
||||
LOGERR("failed to add %s to server list\n",
|
||||
GUID_format1(&switchTypeGuid, s));
|
||||
goto Away;
|
||||
}
|
||||
|
||||
atomic_inc(&UisUtils_Registered_Services);
|
||||
rc = 1; /* success */
|
||||
Away:
|
||||
if (rc) {
|
||||
if (chipset_DriverInfo)
|
||||
BusDeviceInfo_Init(chipset_DriverInfo,
|
||||
"chipset", "uislib",
|
||||
VERSION, NULL,
|
||||
__DATE__, __TIME__);
|
||||
} else
|
||||
LOGERR("failed to register type %s.\n",
|
||||
GUID_format1(&switchTypeGuid, s));
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex);
|
||||
|
||||
int
|
||||
uisctrl_unregister_req_handler_ex(GUID switchTypeGuid)
|
||||
{
|
||||
char s[99];
|
||||
int rc = 0; /* assume failure */
|
||||
LOGINF("type=%s.\n", GUID_format1(&switchTypeGuid, s));
|
||||
if (ReqHandlerDel(switchTypeGuid) < 0) {
|
||||
LOGERR("failed to remove %s from server list\n",
|
||||
GUID_format1(&switchTypeGuid, s));
|
||||
goto Away;
|
||||
}
|
||||
atomic_dec(&UisUtils_Registered_Services);
|
||||
rc = 1; /* success */
|
||||
Away:
|
||||
if (!rc)
|
||||
LOGERR("failed to unregister type %s.\n",
|
||||
GUID_format1(&switchTypeGuid, s));
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex);
|
||||
|
||||
/*
|
||||
* unsigned int util_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
|
||||
* void *skb_in,
|
||||
* unsigned int firstfraglen,
|
||||
* unsigned int frags_max,
|
||||
* struct phys_info frags[])
|
||||
*
|
||||
* calling_ctx - input - a string that is displayed to show
|
||||
* who called * this func
|
||||
* void *skb_in - skb whose frag info we're copying type is hidden so we
|
||||
* don't need to include skbbuff in uisutils.h which is
|
||||
* included in non-networking code.
|
||||
* unsigned int firstfraglen - input - length of first fragment in skb
|
||||
* unsigned int frags_max - input - max len of frags array
|
||||
* struct phys_info frags[] - output - frags array filled in on output
|
||||
* return value indicates number of
|
||||
* entries filled in frags
|
||||
*/
|
||||
unsigned int
|
||||
util_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in,
|
||||
unsigned int firstfraglen, unsigned int frags_max,
|
||||
struct phys_info frags[])
|
||||
{
|
||||
unsigned int count = 0, ii, size, offset = 0, numfrags;
|
||||
struct sk_buff *skb = skb_in;
|
||||
|
||||
numfrags = skb_shinfo(skb)->nr_frags;
|
||||
|
||||
while (firstfraglen) {
|
||||
if (count == frags_max) {
|
||||
LOGERR("%s frags array too small: max:%d count:%d\n",
|
||||
calling_ctx, frags_max, count);
|
||||
return -1; /* failure */
|
||||
}
|
||||
frags[count].pi_pfn =
|
||||
page_to_pfn(virt_to_page(skb->data + offset));
|
||||
frags[count].pi_off =
|
||||
(unsigned long) (skb->data + offset) & PI_PAGE_MASK;
|
||||
size =
|
||||
min(firstfraglen,
|
||||
(unsigned int) (PI_PAGE_SIZE - frags[count].pi_off));
|
||||
/* can take smallest of firstfraglen(what's left) OR
|
||||
* bytes left in the page
|
||||
*/
|
||||
frags[count].pi_len = size;
|
||||
firstfraglen -= size;
|
||||
offset += size;
|
||||
count++;
|
||||
}
|
||||
if (numfrags) {
|
||||
if ((count + numfrags) > frags_max) {
|
||||
LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n",
|
||||
calling_ctx, frags_max, count + numfrags);
|
||||
return -1; /* failure */
|
||||
}
|
||||
|
||||
for (ii = 0; ii < numfrags; ii++) {
|
||||
count = add_physinfo_entries(page_to_pfn(skb_frag_page(&skb_shinfo(skb)->frags[ii])), /* pfn */
|
||||
skb_shinfo(skb)->frags[ii].
|
||||
page_offset,
|
||||
skb_shinfo(skb)->frags[ii].
|
||||
size, count, frags_max,
|
||||
frags);
|
||||
if (count == 0) {
|
||||
LOGERR("**** FAILED to add physinfo entries\n");
|
||||
return -1; /* failure */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (skb_shinfo(skb)->frag_list) {
|
||||
struct sk_buff *skbinlist;
|
||||
int c;
|
||||
for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist;
|
||||
skbinlist = skbinlist->next) {
|
||||
|
||||
c = util_copy_fragsinfo_from_skb("recursive", skbinlist,
|
||||
skbinlist->len -
|
||||
skbinlist->data_len,
|
||||
frags_max - count,
|
||||
&frags[count]);
|
||||
if (c == -1) {
|
||||
LOGERR("**** FAILED recursive call failed\n");
|
||||
return -1;
|
||||
}
|
||||
count += c;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(util_copy_fragsinfo_from_skb);
|
||||
|
||||
static LIST_HEAD(ReqHandlerInfo_list); /* list of ReqHandlerInfo_t */
|
||||
static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock);
|
||||
|
||||
ReqHandlerInfo_t *
|
||||
ReqHandlerAdd(GUID switchTypeGuid,
|
||||
const char *switch_type_name,
|
||||
int (*controlfunc)(struct io_msgs *),
|
||||
unsigned long min_channel_bytes,
|
||||
int (*Server_Channel_Ok)(unsigned long channelBytes),
|
||||
int (*Server_Channel_Init)
|
||||
(void *x, unsigned char *clientStr, U32 clientStrLen, U64 bytes))
|
||||
{
|
||||
ReqHandlerInfo_t *rc = NULL;
|
||||
|
||||
rc = UISMALLOC(sizeof(*rc), GFP_ATOMIC);
|
||||
if (!rc)
|
||||
return NULL;
|
||||
memset(rc, 0, sizeof(*rc));
|
||||
rc->switchTypeGuid = switchTypeGuid;
|
||||
rc->controlfunc = controlfunc;
|
||||
rc->min_channel_bytes = min_channel_bytes;
|
||||
rc->Server_Channel_Ok = Server_Channel_Ok;
|
||||
rc->Server_Channel_Init = Server_Channel_Init;
|
||||
if (switch_type_name)
|
||||
strncpy(rc->switch_type_name, switch_type_name,
|
||||
sizeof(rc->switch_type_name) - 1);
|
||||
spin_lock(&ReqHandlerInfo_list_lock);
|
||||
list_add_tail(&(rc->list_link), &ReqHandlerInfo_list);
|
||||
spin_unlock(&ReqHandlerInfo_list_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
ReqHandlerInfo_t *
|
||||
ReqHandlerFind(GUID switchTypeGuid)
|
||||
{
|
||||
struct list_head *lelt, *tmp;
|
||||
ReqHandlerInfo_t *entry = NULL;
|
||||
spin_lock(&ReqHandlerInfo_list_lock);
|
||||
list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
|
||||
entry = list_entry(lelt, ReqHandlerInfo_t, list_link);
|
||||
if (memcmp
|
||||
(&entry->switchTypeGuid, &switchTypeGuid,
|
||||
sizeof(GUID)) == 0) {
|
||||
spin_unlock(&ReqHandlerInfo_list_lock);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
spin_unlock(&ReqHandlerInfo_list_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
ReqHandlerDel(GUID switchTypeGuid)
|
||||
{
|
||||
struct list_head *lelt, *tmp;
|
||||
ReqHandlerInfo_t *entry = NULL;
|
||||
int rc = -1;
|
||||
spin_lock(&ReqHandlerInfo_list_lock);
|
||||
list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
|
||||
entry = list_entry(lelt, ReqHandlerInfo_t, list_link);
|
||||
if (memcmp
|
||||
(&entry->switchTypeGuid, &switchTypeGuid,
|
||||
sizeof(GUID)) == 0) {
|
||||
list_del(lelt);
|
||||
UISFREE(entry, sizeof(*entry));
|
||||
rc++;
|
||||
}
|
||||
}
|
||||
spin_unlock(&ReqHandlerInfo_list_lock);
|
||||
return rc;
|
||||
}
|
Loading…
Reference in a new issue