aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mvp/commkm
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /arch/arm/mvp/commkm
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2
samsung update 1
Diffstat (limited to 'arch/arm/mvp/commkm')
-rw-r--r--arch/arm/mvp/commkm/COPYING341
-rw-r--r--arch/arm/mvp/commkm/Kbuild9
-rw-r--r--arch/arm/mvp/commkm/Makefile1
-rw-r--r--arch/arm/mvp/commkm/check_kconfig.c91
-rw-r--r--arch/arm/mvp/commkm/comm.c1457
-rw-r--r--arch/arm/mvp/commkm/comm.h171
-rw-r--r--arch/arm/mvp/commkm/comm_ev.h51
-rw-r--r--arch/arm/mvp/commkm/comm_ev_kernel.c136
-rw-r--r--arch/arm/mvp/commkm/comm_os.h150
-rw-r--r--arch/arm/mvp/commkm/comm_os_linux.c371
-rw-r--r--arch/arm/mvp/commkm/comm_os_linux.h699
-rw-r--r--arch/arm/mvp/commkm/comm_os_mod_linux.c105
-rw-r--r--arch/arm/mvp/commkm/comm_os_mod_ver.h38
-rw-r--r--arch/arm/mvp/commkm/comm_svc.c421
-rw-r--r--arch/arm/mvp/commkm/comm_svc.h71
-rw-r--r--arch/arm/mvp/commkm/comm_transp.h90
-rw-r--r--arch/arm/mvp/commkm/comm_transp_impl.h165
-rw-r--r--arch/arm/mvp/commkm/comm_transp_mvp.c944
-rw-r--r--arch/arm/mvp/commkm/fatalerror.h126
-rw-r--r--arch/arm/mvp/commkm/include_check.h18
-rw-r--r--arch/arm/mvp/commkm/mksck.h153
-rw-r--r--arch/arm/mvp/commkm/mksck_sockaddr.h50
-rw-r--r--arch/arm/mvp/commkm/mvp.h48
-rw-r--r--arch/arm/mvp/commkm/mvp_assert.h125
-rw-r--r--arch/arm/mvp/commkm/mvp_compiler.h56
-rw-r--r--arch/arm/mvp/commkm/mvp_compiler_gcc.h87
-rw-r--r--arch/arm/mvp/commkm/mvp_types.h94
-rw-r--r--arch/arm/mvp/commkm/mvpkm_comm_ev.h53
-rw-r--r--arch/arm/mvp/commkm/nottested.h54
-rw-r--r--arch/arm/mvp/commkm/platdefx.h67
-rw-r--r--arch/arm/mvp/commkm/qp.h332
-rw-r--r--arch/arm/mvp/commkm/utils.h172
-rw-r--r--arch/arm/mvp/commkm/vmid.h44
33 files changed, 6790 insertions, 0 deletions
diff --git a/arch/arm/mvp/commkm/COPYING b/arch/arm/mvp/commkm/COPYING
new file mode 100644
index 0000000..10828e0
--- /dev/null
+++ b/arch/arm/mvp/commkm/COPYING
@@ -0,0 +1,341 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/arch/arm/mvp/commkm/Kbuild b/arch/arm/mvp/commkm/Kbuild
new file mode 100644
index 0000000..de43a5c
--- /dev/null
+++ b/arch/arm/mvp/commkm/Kbuild
@@ -0,0 +1,9 @@
+# Warning: autogenerated
+obj-m := commkm.o
+commkm-objs := check_kconfig.o comm_ev_kernel.o comm.o comm_os_linux.o comm_os_mod_linux.o comm_svc.o comm_transp_mvp.o
+
+ccflags-y += -fno-pic -fno-dwarf2-cfi-asm -march=armv7-a -D__linux__
+ccflags-y += -DCOMM_BUILDING_SERVER
+ccflags-y += -mfpu=neon -DIN_MODULE -DGPLED_CODE
+ccflags-y += --std=gnu89 -O2 -g2 -ggdb -mapcs -fno-optimize-sibling-calls -mno-sched-prolog
+ccflags-$(CONFIG_VMWARE_MVP_DEBUG) += -DMVP_DEBUG
diff --git a/arch/arm/mvp/commkm/Makefile b/arch/arm/mvp/commkm/Makefile
new file mode 100644
index 0000000..16eb389
--- /dev/null
+++ b/arch/arm/mvp/commkm/Makefile
@@ -0,0 +1 @@
+# Warning: autogenerated
diff --git a/arch/arm/mvp/commkm/check_kconfig.c b/arch/arm/mvp/commkm/check_kconfig.c
new file mode 100644
index 0000000..0867d74
--- /dev/null
+++ b/arch/arm/mvp/commkm/check_kconfig.c
@@ -0,0 +1,91 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ * @brief Check for required kernel configuration
+ *
+ * Check to make sure that the kernel options that the MVP hypervisor requires
+ * have been enabled in the kernel that this kernel module is being built
+ * against.
+ */
+#include <linux/version.h>
+
+/*
+ * Minimum kernel version
+ * - network namespace support is only really functional starting in 2.6.29
+ * - Android Gingerbread requires 2.6.35
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+#error "MVP requires a host kernel newer than 2.6.35"
+#endif
+
+/* module loading ability */
+#ifndef CONFIG_MODULES
+#error "MVP requires kernel loadable module support be enabled (CONFIG_MODULES)"
+#endif
+#ifndef CONFIG_MODULE_UNLOAD
+#error "MVP requires kernel module unload support be enabled (CONFIG_MODULE_UNLOAD)"
+#endif
+
+/* sysfs */
+#ifndef CONFIG_SYSFS
+#error "MVP requires sysfs support (CONFIG_SYSFS)"
+#endif
+
+/* network traffic isolation */
+#ifndef CONFIG_NAMESPACES
+#error "MVP networking support requires namespace support (CONFIG_NAMESPACES)"
+#endif
+#ifndef CONFIG_NET_NS
+#error "MVP networking support requires Network Namespace support to be enabled (CONFIG_NET_NS)"
+#endif
+
+/* TCP/IP networking */
+#ifndef CONFIG_INET
+#error "MVP networking requires IPv4 support (CONFIG_INET)"
+#endif
+#ifndef CONFIG_IPV6
+#error "MVP networking requires IPv6 support (CONFIG_IPV6)"
+#endif
+
+/* VPN support */
+#if !defined(CONFIG_TUN) && !defined(CONFIG_TUN_MODULE)
+#error "MVP VPN support requires TUN device support (CONFIG_TUN)"
+#endif
+
+#if !defined(CONFIG_NETFILTER) && !defined(PVTCP_DISABLE_NETFILTER)
+#error "MVP networking support requires netfilter support (CONFIG_NETFILTER)"
+#endif
+
+/* Force /proc/config.gz support for eng/userdebug builds */
+#ifdef MVP_DEBUG
+#if !defined(CONFIG_IKCONFIG) || !defined(CONFIG_IKCONFIG_PROC)
+#error "MVP kernel /proc/config.gz support required for debuggability (CONFIG_IKCONFIG_PROC)"
+#endif
+#endif
+
+/* Sanity check we're only dealing with the memory hotplug + migrate and/or
+ * compaction combo */
+#ifdef CONFIG_MIGRATION
+#if defined(CONFIG_NUMA) || defined(CONFIG_CPUSETS) || defined(CONFIG_MEMORY_FAILURE)
+#error "MVP not tested with migration features other than CONFIG_MEMORY_HOTPLUG and CONFIG_COMPACTION"
+#endif
+#endif
diff --git a/arch/arm/mvp/commkm/comm.c b/arch/arm/mvp/commkm/comm.c
new file mode 100644
index 0000000..8fd591c
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm.c
@@ -0,0 +1,1457 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Communication functions based on transport functionality.
+ */
+
+#include "comm.h"
+#include "comm_transp_impl.h"
+
+
+/* Constant and macro definitions */
+
+#if defined(COMM_INSTRUMENT)
+static CommOSAtomic commMaxCoalesceSize;
+static CommOSAtomic commPacketsReceived;
+static CommOSAtomic commCommittedPacketsReceived;
+static CommOSAtomic commOpCalls;
+#endif
+
+#define COMM_DISPATCH_EXTRA_WRITER_WAKEUP 1
+
+#define COMM_CHANNEL_MAX_CAPACITY 2048
+#define COMM_CHANNEL_FREE 0x0
+#define COMM_CHANNEL_INITIALIZED 0x1
+#define COMM_CHANNEL_OPENED 0x2
+#define COMM_CHANNEL_ACTIVE 0x4
+#define COMM_CHANNEL_ZOMBIE 0x8
+
+#define CommIsFree(chan) \
+ ((chan)->lifecycleState == COMM_CHANNEL_FREE)
+#define CommIsInitialized(chan) \
+ ((chan)->lifecycleState == COMM_CHANNEL_INITIALIZED)
+#define CommIsOpened(chan) \
+ ((chan)->lifecycleState == COMM_CHANNEL_OPENED)
+#define CommIsActive(chan) \
+ ((chan)->lifecycleState == COMM_CHANNEL_ACTIVE)
+#define CommIsZombie(chan) \
+ ((chan)->lifecycleState == COMM_CHANNEL_ZOMBIE)
+
+#define CommSetFree(chan) \
+ SetLifecycleState(chan, COMM_CHANNEL_FREE)
+#define CommSetInitialized(chan) \
+ SetLifecycleState(chan, COMM_CHANNEL_INITIALIZED)
+#define CommSetOpened(chan) \
+ SetLifecycleState(chan, COMM_CHANNEL_OPENED)
+#define CommSetActive(chan) \
+ SetLifecycleState(chan, COMM_CHANNEL_ACTIVE)
+#define CommSetZombie(chan) \
+ SetLifecycleState(chan, COMM_CHANNEL_ZOMBIE)
+
+#define CommGlobalLock() CommOS_SpinLock(&commGlobalLock)
+#define CommGlobalUnlock() CommOS_SpinUnlock(&commGlobalLock)
+#define CommGlobalLockBH() CommOS_SpinLockBH(&commGlobalLock)
+#define CommGlobalUnlockBH() CommOS_SpinUnlockBH(&commGlobalLock)
+
+#define DispatchTrylock(chan) CommOS_MutexTrylock(&(chan)->dispatchMutex)
+#define DispatchUnlock(chan) CommOS_MutexUnlock(&(chan)->dispatchMutex)
+
+#define WriteLock(chan) CommOS_MutexLock(&(chan)->writeMutex)
+#define WriteTrylock(chan) CommOS_MutexTrylock(&(chan)->writeMutex)
+#define WriteUnlock(chan) CommOS_MutexUnlock(&(chan)->writeMutex)
+
+#define StateLock(chan) CommOS_MutexLock(&(chan)->stateMutex)
+#define StateTrylock(chan) CommOS_MutexTrylock(&(chan)->stateMutex)
+#define StateUnlock(chan) CommOS_MutexUnlock(&(chan)->stateMutex)
+
+#define CommHoldInit(chan) CommOS_WriteAtomic(&(chan)->holds, 0)
+#define CommHold(chan) CommOS_AddReturnAtomic(&(chan)->holds, 1)
+#define CommRelease(chan) CommOS_SubReturnAtomic(&(chan)->holds, 1)
+#define CommIsHeld(chan) (CommOS_ReadAtomic(&(chan)->holds) > 0)
+
+#define PacketLenOverLimit(chan, len) \
+ (((len) - sizeof (CommPacket)) > ((chan)->transpArgs.capacity / 4))
+
+
+/*
+ * Data structure describing the offload <-> paravirtualized module
+ * communication channel.
+ */
+
+struct CommChannelPriv {
+ CommOSAtomic holds; // Active readers and writers
+ CommTranspInitArgs transpArgs; // Transport initialization arguments
+ CommTransp transp; // Transport handle
+ CommOSMutex dispatchMutex; // Dispatch mutex
+ CommOSMutex writeMutex; // Non-BH write mutex
+ CommOSMutex stateMutex; // Upper-layer state mutex
+ CommOSWaitQueue availableWaitQ; // Available write space wait data
+ unsigned int desiredWriteSpace; // Size of write space needed
+ const CommImpl *impl; // Implementation
+ unsigned int implNmbOps; // Number of implementation operations
+ unsigned int lifecycleState; // Lifecycle state
+ void *state; // Upper layer-specific state
+};
+
+
+static volatile int running; // Initialized and running.
+static CommOSWaitQueue exitWaitQ; // Exit wait queue.
+static CommOSSpinlock commGlobalLock; // Global lock.
+
+
+/* Communication channel slots. */
+
+static unsigned int commChannelCapacity; // Maximum number of channels.
+static unsigned int commChannelSize; // Current size of channel array.
+static unsigned int commChannelAllocated; // Nmb. entries currently in use.
+static struct CommChannelPriv *commChannels; // Allocated channel array.
+
+
+/**
+ * @brief Callback function called when the other side created a transport
+ * handle to which we need to potentially attach.
+ * @param[in,out] transpArgs arguments used when shared memory area was created.
+ * @param probeData our callback data, an implementation block.
+ * @return 0 if successful, -1 otherwise.
+ * @sideeffects May allocate a channel.
+ */
+
+static int
+DefaultTranspListener(CommTranspInitArgs *transpArgs,
+ void *probeData)
+{
+ int rc = -1;
+ const int inBH = 1;
+ const CommImpl *impl;
+
+ if (!transpArgs || !probeData) {
+ CommOS_Debug(("%s: NULL args [0x%p, 0x%p].\n",
+ __FUNCTION__, transpArgs, probeData));
+ goto out;
+ }
+
+ impl = probeData;
+ CommOS_Debug(("%s: Received attach info [%u,%u,%u:%u].\n",
+ __FUNCTION__,
+ transpArgs->capacity, transpArgs->type,
+ transpArgs->id.d32[0], transpArgs->id.d32[1]));
+
+ if (impl->checkArgs(transpArgs)) {
+ goto out;
+ }
+ transpArgs->mode = COMM_TRANSP_INIT_ATTACH; /* Ensure we attach. */
+
+ /* We recognized it, so don't let others waste any time. Even if we fail. */
+
+ rc = 0;
+ if (Comm_Alloc(transpArgs, impl, inBH, NULL)) {
+ impl->closeNtf(impl->closeNtfData, transpArgs, inBH);
+ CommOS_Log(("%s: Can't allocate new channel!\n", __FUNCTION__));
+ }
+
+out:
+ return rc;
+}
+
+
+/**
+ * @brief Sets the lifecycle state of a channel entry
+ * @param channel channel to update
+ * @param newState state to update to
+ */
+
+static inline void
+SetLifecycleState(CommChannel channel,
+ unsigned int newState)
+{
+
+ channel->lifecycleState = newState;
+}
+
+
+/* Wait conditions: functions returning 1: true, 0: false, < 0: error. */
+
+/**
+ * @brief Wait condition function to check whether module can be unloaded.
+ * @param arg1 dummy
+ * @param arg2 dummy
+ * @return 1 if no channels are currently allocated, 0 if there are
+ */
+
+static int
+ExitCondition(void *arg1,
+ void *arg2)
+{
+ unsigned int i;
+ int rc;
+
+ (void)arg1;
+ (void)arg2;
+ CommOS_Debug(("%s: running [%d] "
+ "commChannelAllocated [%u] commChannelSize [%u].\n",
+ __FUNCTION__, running, commChannelAllocated, commChannelSize));
+ rc = !running && (commChannelAllocated == 0);
+ if (!rc) {
+ for (i = 0; i < commChannelCapacity; i++) {
+ CommOS_Debug(("%s: channel[%u] state [0x%x].\n",
+ __FUNCTION__, i, commChannels[i].lifecycleState));
+ }
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Wait condition function to check available write space.
+ * @param arg1 pointer to CommChannel struct
+ * @param arg2 size argument
+ * @return 1 if there is enough write space, 0 if not, -ENOMEM if comm down.
+ */
+
+static int
+WriteSpaceCondition(void *arg1,
+ void *arg2)
+{
+ CommChannel channel = arg1;
+
+ if (!CommIsActive(channel)) {
+ return -ENOMEM;
+ }
+ return channel->desiredWriteSpace < CommTransp_EnqueueSpace(channel->transp);
+}
+
+
+/**
+ * @brief Registers an implementation block used when attaching to channels
+ * in response to transport attach events.
+ * @param impl implementation block.
+ * @return 0 if successful, non-zero otherwise.
+ */
+
+int
+Comm_RegisterImpl(const CommImpl *impl)
+{
+ CommTranspListener listener = {
+ .probe = DefaultTranspListener,
+ .probeData = (void *)impl
+ };
+
+ return CommTransp_Register(&listener);
+}
+
+
+/**
+ * @brief Unregisters an implementation block used when attaching to channels
+ * in response to transport attach events.
+ * @param impl implementation block.
+ */
+
+void
+Comm_UnregisterImpl(const CommImpl *impl)
+{
+ CommTranspListener listener = {
+ .probe = DefaultTranspListener,
+ .probeData = (void *)impl
+ };
+
+ CommTransp_Unregister(&listener);
+}
+
+
+/**
+ * @brief Allocates and initializes comm global state. Single-threaded use.
+ * @param maxChannels maximum number of channels.
+ * @return zero if successful, non-zero otherwise.
+ */
+
+int
+Comm_Init(unsigned int maxChannels)
+{
+ int rc = -1;
+ unsigned int i;
+
+ if (running || commChannels ||
+ (maxChannels == 0) || (maxChannels > COMM_CHANNEL_MAX_CAPACITY)) {
+ goto out;
+ }
+
+#if defined(COMM_INSTRUMENT)
+ CommOS_WriteAtomic(&commMaxCoalesceSize, 0);
+ CommOS_WriteAtomic(&commPacketsReceived, 0);
+ CommOS_WriteAtomic(&commCommittedPacketsReceived, 0);
+ CommOS_WriteAtomic(&commOpCalls, 0);
+#endif
+
+ CommOS_WaitQueueInit(&exitWaitQ);
+ CommOS_SpinlockInit(&commGlobalLock);
+ commChannelCapacity = maxChannels;
+ commChannelAllocated = 0;
+ commChannels = CommOS_Kmalloc((sizeof *commChannels) * commChannelCapacity);
+ if (!commChannels) {
+ goto out;
+ }
+
+ memset(commChannels, 0, (sizeof *commChannels) * commChannelCapacity);
+ for (i = 0; i < commChannelCapacity; i++ ) {
+ CommChannel channel;
+
+ channel = &commChannels[i];
+ CommHoldInit(channel);
+ channel->transp = NULL;
+ CommOS_MutexInit(&channel->dispatchMutex);
+ CommOS_MutexInit(&channel->writeMutex);
+ CommOS_MutexInit(&channel->stateMutex);
+ CommOS_WaitQueueInit(&channel->availableWaitQ);
+ channel->desiredWriteSpace = -1U;
+ channel->state = NULL;
+ CommSetFree(channel);
+ }
+
+ rc = CommTransp_Init();
+ if (!rc) {
+ commChannelSize = 0;
+ running = 1;
+ rc = 0;
+ } else {
+ CommOS_Kfree(commChannels);
+ }
+
+out:
+ return rc;
+}
+
+
+/**
+ * @brief Initiates and finishes, comm global state deallocations.
+ * @param timeoutMillis initialization timeout in milliseconds
+ * @return zero if deallocations done, non-zero if more calls are needed.
+ */
+
+int
+Comm_Finish(unsigned long long *timeoutMillis)
+{
+ int rc;
+ unsigned int i;
+ unsigned long long timeout;
+
+ for (i = 0; i < commChannelSize; i++) {
+ Comm_Zombify(&commChannels[i], 0);
+ }
+
+ running = 0;
+ timeout = timeoutMillis ? *timeoutMillis : 0;
+ /* coverity[var_deref_model] */
+ rc = CommOS_Wait(&exitWaitQ, ExitCondition, NULL, NULL, &timeout);
+ if (rc == 1) {
+ /*
+ * Didn't time out, task wasn't interrupted, we can wrap it up..
+ */
+
+ CommTransp_Exit();
+ CommOS_Kfree(commChannels);
+ commChannels = NULL;
+ commChannelSize = 0;
+#if defined(COMM_INSTRUMENT)
+ CommOS_Log(("%s: commMaxCoalesceSize = %lu.\n",
+ __FUNCTION__,
+ CommOS_ReadAtomic(&commMaxCoalesceSize)));
+ CommOS_Log(("%s: commPacketsReceived = %lu.\n",
+ __FUNCTION__,
+ CommOS_ReadAtomic(&commPacketsReceived)));
+ CommOS_Log(("%s: commCommittedPacketsReceived = %lu.\n",
+ __FUNCTION__,
+ CommOS_ReadAtomic(&commCommittedPacketsReceived)));
+ CommOS_Log(("%s: commOpCalls = %lu.\n",
+ __FUNCTION__,
+ CommOS_ReadAtomic)(&commOpCalls)));
+#endif
+ rc = 0;
+ } else {
+ rc = -1;
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Finds a free entry and initializes it with the information provided.
+ * May be called from BH. It doesn't call potentially blocking functions.
+ *
+ * @note Depending on the choice of shared memory transport (VMCI or MVP QP),
+ * the 'inBH' distinction is important. VMCI datagrams are received under
+ * some circumstances in bottom-half context, so 'inBH' should be set. This
+ * is not a restriction on MVP.
+ *
+ * @param transpArgs transport initialization arguments.
+ * @param impl implementation block.
+ * @param inBH non-zero if called in bottom half.
+ * @param[out] newChannel newly allocated channel.
+ * @return zero if successful, non-zero otherwise.
+ * @sideeffects Initializes the communications channel with given parameters
+ */
+
+int
+Comm_Alloc(const CommTranspInitArgs *transpArgs,
+ const CommImpl *impl,
+ int inBH,
+ CommChannel *newChannel)
+{
+ unsigned int i;
+ CommChannel channel = NULL;
+ int restoreSize = 0;
+ int modHeld = 0;
+ int rc = -1;
+
+ if (inBH) {
+ CommGlobalLock();
+ } else {
+ CommGlobalLockBH();
+ }
+
+ if (!running || !transpArgs || !impl) {
+ goto out;
+ }
+
+ if (CommOS_ModuleGet(impl->owner)) {
+ goto out;
+ }
+ modHeld = 1;
+
+ for (i = 0; i < commChannelSize; i++) {
+ /*
+ * Check if this channel is already allocated. We don't match against
+ * ANY because those channels are in the process of being opened; after
+ * that happens, they'll get proper IDs.
+ */
+
+ if (!CommIsFree(&commChannels[i]) &&
+ (transpArgs->id.d64 != COMM_TRANSP_ID_64_ANY) &&
+ (transpArgs->id.d64 == commChannels[i].transpArgs.id.d64)) {
+ goto out;
+ }
+ if (!channel && CommIsFree(&commChannels[i])) {
+ channel = &commChannels[i];
+ }
+ }
+ if (!channel) {
+ if (commChannelSize == commChannelCapacity) {
+ goto out;
+ }
+ channel = &commChannels[commChannelSize];
+ commChannelSize++;
+ restoreSize = 1;
+ }
+
+ if (channel->transp) { /* Inconsistency! */
+ if (restoreSize) {
+ commChannelSize--;
+ }
+ goto out;
+ }
+
+ channel->transpArgs = *transpArgs;
+ channel->impl = impl;
+ for (i = 0; impl->operations[i]; i++) {
+ ;
+ }
+ channel->implNmbOps = i;
+ channel->desiredWriteSpace = -1U;
+ commChannelAllocated++;
+ CommSetInitialized(channel);
+ if (newChannel) {
+ *newChannel = channel;
+ }
+ rc = 0;
+ CommOS_ScheduleDisp();
+
+out:
+ if (inBH) {
+ CommGlobalUnlock();
+ } else {
+ CommGlobalUnlockBH();
+ }
+ if (rc && modHeld) {
+ CommOS_ModulePut(impl->owner);
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Zombifies a channel. May fail if channel isn't active.
+ * @param[in,out] channel channel to zombify.
+ * @param inBH non-zero if called in bottom half.
+ * @return zero if channel zombified, non-zero otherwise.
+ */
+
+int
+Comm_Zombify(CommChannel channel,
+ int inBH)
+{
+ int rc = -1;
+
+ if (!running) {
+ goto out;
+ }
+ if (inBH) {
+ CommGlobalLock();
+ } else {
+ CommGlobalLockBH();
+ }
+ if (CommIsActive(channel) || CommIsOpened(channel)) {
+ CommSetZombie(channel);
+ rc = 0;
+ }
+ if (inBH) {
+ CommGlobalUnlock();
+ } else {
+ CommGlobalUnlockBH();
+ }
+
+out:
+ if (!rc) {
+ CommOS_ScheduleDisp();
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Reports whether a channel is active.
+ * @param channel channel to report on.
+ * @return non-zero if channel active, zero otherwise.
+ */
+
+int
+Comm_IsActive(CommChannel channel)
+{
+ return channel ? CommIsActive(channel) : 0;
+}
+
+
+/**
+ * @brief Wakes up potential writer on the channel. This function must be
+ * called on an active channel, with either the dispatch lock taken, or
+ * the channel ref count incremented.
+ * @param channel CommChannel structure on which potential writer waits.
+ */
+
+static inline void
+WakeUpWriter(CommChannel channel)
+{
+ if (WriteSpaceCondition(channel, NULL)) {
+ CommOS_WakeUp(&channel->availableWaitQ);
+ }
+}
+
+
+/**
+ * @brief Transport event handler for comm channels.
+ * @param transp transport handle.
+ * @param event type of event.
+ * @param data callback data.
+ * @sideeffects may put the channel into zombie state, or schedule it for I/O.
+ */
+
+static void
+TranspEventHandler(CommTransp transp,
+ CommTranspIOEvent event,
+ void *data)
+{
+ CommChannel channel = (CommChannel)data;
+
+ switch (event) {
+ case COMM_TRANSP_IO_DETACH:
+ CommOS_Debug(("%s: Detach event. Zombifying channel.\n", __FUNCTION__));
+ Comm_Zombify(channel, 1);
+ break;
+
+ case COMM_TRANSP_IO_IN:
+ case COMM_TRANSP_IO_INOUT:
+ /*
+ * The dispatch threads may not have been started because either:
+ * a) we're not running in the CommSvc service, or
+ * b) the Comm client didn't create them explicitly (CommOS_StartIO()).
+ *
+ * If so, the CommOS_ScheduleDisp() call is ineffective. This is
+ * the intended behavior: the client obviously wants to call the Comm
+ * dispatch function(s) directly.
+ */
+
+ CommOS_ScheduleDisp();
+ break;
+
+ case COMM_TRANSP_IO_OUT:
+ CommHold(channel);
+ if (CommIsActive(channel)) {
+ WakeUpWriter(channel);
+ }
+ CommRelease(channel);
+ if (CommIsZombie(channel)) {
+ /*
+ * After releasing the hold on the channel, we must check if it was
+ * set to zombie and the dispatcher was supposed to nuke it. If the
+ * dispatcher had made its run while we were holding the channel, it
+ * gave up. So schedule it.
+ */
+
+ CommOS_ScheduleDisp();
+ }
+ break;
+
+ default:
+ CommOS_Debug(("%s: Unhandled event [%u, %p, %p].\n",
+ __FUNCTION__, event, transp, data));
+ }
+}
+
+
+/**
+ * @brief Destroys upper layer state, unregisters event handlers and
+ * detaches from or deletes shared memory.
+ * @param[in,out] channel CommChannel structure to close.
+ */
+
+static void
+CommClose(CommChannel channel)
+{
+ const CommImpl *impl = channel->impl;
+
+ StateLock(channel);
+ if (impl->stateDtor && channel->state) {
+ impl->stateDtor(channel->state);
+ }
+ channel->state = NULL;
+ StateUnlock(channel);
+
+ CommOS_ModulePut(impl->owner);
+
+ if (channel->transp) {
+ CommTransp_Close(channel->transp);
+ channel->transp = NULL;
+ }
+
+ CommGlobalLockBH();
+ CommSetFree(channel);
+ commChannelAllocated--;
+ if (channel == &commChannels[commChannelSize - 1]) {
+ commChannelSize--;
+ }
+ CommGlobalUnlockBH();
+ if (!running && (commChannelAllocated == 0)) {
+ CommOS_WakeUp(&exitWaitQ);
+ }
+}
+
+
+/**
+ * @brief Allocates upper layer state, registers transport event handler
+ * and creates or attaches to shared memory.
+ * @param[in,out] channel CommChannel structure to open.
+ * @return zero if successful, -1 otherwise
+ * @sideeffects Memory may be allocated, event handlers registered and
+ * QP allocated or attached to.
+ */
+
+static int
+CommOpen(CommChannel channel)
+{
+ int rc = -1;
+ CommTranspEvent transpEvent = {
+ .ioEvent = TranspEventHandler,
+ .ioEventData = channel
+ };
+ const CommImpl *impl;
+
+ if (!channel || !CommIsInitialized(channel)) {
+ return rc;
+ }
+
+ if (!running) { /* Ok, toggle it back to FREE. */
+ goto out;
+ }
+
+ impl = channel->impl;
+ if (impl->stateCtor) {
+ channel->state = impl->stateCtor(channel);
+ if (!channel->state) {
+ goto out;
+ }
+ }
+
+ if (!CommTransp_Open(&channel->transp, &channel->transpArgs, &transpEvent)) {
+ rc = 0;
+ } else {
+ channel->transp = NULL;
+ }
+
+out:
+ if (!rc) {
+ CommSetOpened(channel);
+ } else {
+ CommClose(channel);
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Retrieves a channel's transport initialization arguments.
+ * It doesn't lock, the caller must ensure the channel may be accessed.
+ * @param channel CommChannel structure to get initialization arguments from.
+ * @return initialization arguments used to allocate/attach to channel.
+ */
+
+CommTranspInitArgs
+Comm_GetTranspInitArgs(CommChannel channel)
+{
+ if (!channel) {
+ CommTranspInitArgs res = { .capacity = 0 };
+
+ return res;
+ }
+ return channel->transpArgs;
+}
+
+
+/**
+ * @brief Retrieves upper layer state (pointer). It doesn't lock, the caller
+ * must ensure the channel may be accessed.
+ * @param channel CommChannel structure to get state from.
+ * @return pointer to upper layer state.
+ */
+
+void *
+Comm_GetState(CommChannel channel)
+{
+ if (!channel) {
+ return NULL;
+ }
+ return channel->state;
+}
+
+
+/**
+ * @brief Main input processing function operating on a given channel.
+ * @param channel CommChannel structure to process.
+ * @return number of processed channels (0 or 1), or -1 if channel closed.
+ * @sideeffects Lifecycle states are transitioned to and from. Channel may
+ * be opened or destroyed, waiting writers may be woken up, and input
+ * may be handed off to operation callbacks.
+ */
+
+int
+Comm_Dispatch(CommChannel channel)
+{
+ int rc = 0;
+ int zombify = 0;
+ CommPacket packet;
+ CommPacket firstPacket;
+ unsigned int dataLen;
+#define VEC_SIZE 32
+ struct kvec vec[VEC_SIZE];
+ unsigned int vecLen;
+
+ /*
+ * Taking the reader mutex is safe in all cases: entries, including
+ * free ones, are guaranteed to have initialized mutexes and locks.
+ * Locking empty entries may seem wasteful, but those entries are rare.
+ */
+
+ if (DispatchTrylock(channel)) {
+ return 0;
+ }
+
+ /* Process input and writer wake-up. */
+
+ if (CommIsActive(channel)) {
+ /*
+ * The entry may have transitioned to ZOMBIE, somehow. That's OK
+ * since it can't be freed just yet (it's currently locked).
+ */
+
+ /* Wake up any waiting writers, if necessary. */
+
+ WakeUpWriter(channel);
+
+ /* Read packets, payloads. */
+ CommTransp_DequeueReset(channel->transp);
+
+ for (vecLen = 0; vecLen < VEC_SIZE; vecLen++) {
+ if (!running) {
+ break;
+ }
+
+ /* Read header. */
+
+ rc = CommTransp_DequeueSegment(channel->transp,
+ &packet, sizeof packet);
+ if (rc <= 0) {
+ /* No packet (header). */
+
+ rc = vecLen == 0 ? 0 : 1;
+ break;
+ }
+#if defined(COMM_INSTRUMENT)
+ CommOS_AddReturnAtomic(commPacketsReceived, 1);
+#endif
+ if ((rc != sizeof packet) || (packet.len < sizeof packet)) {
+ rc = -1; /* Fatal protocol error, close down comm. */
+ break;
+ }
+ rc = 1;
+
+ /* Read payload, if any. */
+
+ dataLen = packet.len - sizeof packet;
+ if (vecLen == 0) {
+ /* Save header of first packet. */
+
+ firstPacket = packet;
+ if (dataLen == 0) {
+ /* Commit no-payload packet read and we're done. */
+
+ CommTransp_DequeueCommit(channel->transp);
+#if defined(COMM_INSTRUMENT)
+ CommOS_AddReturnAtomic(&commCommittedPacketsReceived, 1);
+#endif
+ break;
+ }
+ } else {
+ /*
+ * Check if non-equivalent packet or above coalescing limit.
+ * If so, don't commit the read.
+ */
+
+ if (memcmp(&packet.opCode, &firstPacket.opCode,
+ sizeof packet - offsetof(CommPacket, opCode)) ||
+ PacketLenOverLimit(channel, firstPacket.len + dataLen)) {
+ break;
+ }
+ }
+
+ if (dataLen == 0) {
+ /*
+ * Received equivalent packet with zero-sized payload. This may
+ * happen in certain cases, such as pvtcp forwarding zero-sized
+ * datagrams. So don't break the loop, but keep going for as
+ * along as we can.
+ */
+
+ vec[vecLen].iov_base = NULL;
+ goto dequeueCommit;
+ }
+
+ /* The packet has a payload (dataLen > 0). */
+
+ if (!(vec[vecLen].iov_base = channel->impl->dataAlloc(dataLen))) {
+ /*
+ * We treat out-of-(net?-)memory errors as "nothing to read".
+ * Memory pressure may either subside, in which case a future
+ * read may be successful, or be severe enough for the kernel
+ * to oops, anyway. Leave packet uncommitted.
+ */
+
+ CommOS_Debug(("%s: COULD NOT ALLOC PAYLOAD BYTES!\n",
+ __FUNCTION__));
+ rc = vecLen == 0 ? 0 : 1;
+ break;
+ }
+
+ /* Read payload and commit (packet and payload). */
+
+ rc = CommTransp_DequeueSegment(channel->transp,
+ vec[vecLen].iov_base, dataLen);
+ if (rc != dataLen) {
+ channel->impl->dataFree(vec[vecLen].iov_base);
+ CommOS_Log(("%s: BOOG -- COULD NOT DEQUEUE PAYLOAD! [%d != %u]",
+ __FUNCTION__, rc, dataLen));
+ rc = -1; /* Fatal protocol error, close down comm. */
+ break;
+ }
+ rc = 1;
+
+dequeueCommit:
+ CommTransp_DequeueCommit(channel->transp);
+#if defined(COMM_INSTRUMENT)
+ CommOS_AddReturnAtomic(&commCommittedPacketsReceived, 1);
+#endif
+ vec[vecLen].iov_len = dataLen;
+ if (vecLen > 0) {
+ firstPacket.len += dataLen;
+ if (packet.flags) {
+ /* Update to latest flags _iff_ latter non-zero. */
+
+ firstPacket.flags = packet.flags;
+ }
+ }
+#if defined(COMM_INSTRUMENT)
+ if (firstPacket.len >
+ CommOS_ReadAtomic(&commMaxCoalesceSize)) {
+ CommOS_WriteAtomic(&commMaxCoalesceSize, firstPacket.len);
+ }
+#endif
+ if (COMM_OPF_TEST_ERR(packet.flags)) {
+ /* If error bit is set, we're done (no more coalescing). */
+
+ vecLen++;
+ break;
+ }
+ }
+
+ if (rc <= 0) {
+ if (rc < 0) {
+ zombify = 1;
+ rc = 1;
+ }
+ goto outUnlockAndFreeIovec;
+ }
+
+#if defined(COMM_DISPATCH_EXTRA_WRITER_WAKEUP)
+ /* Check again if we need to wake up any writers. */
+
+ WakeUpWriter(channel);
+#endif
+
+ if (firstPacket.opCode >= channel->implNmbOps) {
+ CommOS_Debug(("%s: Ignoring illegal opCode [%u]!\n",
+ __FUNCTION__, (unsigned int)firstPacket.opCode));
+ CommOS_Debug(("%s: Max opCode: %u\n",
+ __FUNCTION__, channel->implNmbOps));
+ goto outUnlockAndFreeIovec;
+ }
+
+ /*
+ * NOTE:
+ * DispatchUnlock() _must_ be called from the operation callback.
+ * The reason for doing so is that, for better scalability, we want
+ * it released as soon as possible, BUT:
+ * - releasing it here, before calling into the operation, doesn't
+ * let the latter coordinate its own lock acquisition, such as
+ * potential socket or state locks.
+ * - alternatively, always releasing the dispatch lock after the
+ * operation completes, ties up the channel and imposes too much
+ * serialization between sockets.
+ * - to prevent the channel from being torn down while an operation
+ * is in flight (and potentially having released the dispatch lock),
+ * we increment the ref count on the channel and then release it
+ * after the function returns.
+ */
+
+#if defined(COMM_INSTRUMENT)
+ CommOS_AddReturnAtomic(&commOpCalls, 1);
+#endif
+
+ CommHold(channel);
+ channel->impl->operations[firstPacket.opCode](channel, channel->state,
+ &firstPacket, vec, vecLen);
+ CommRelease(channel);
+ goto out; /* No unlocking, see comment above. */
+ }
+
+ /* Process state changes. */
+
+ if (CommIsZombie(channel) && !CommIsHeld(channel)) {
+ CommTranspInitArgs transpArgs = channel->transpArgs;
+ void (*closeNtf)(void *,
+ const CommTranspInitArgs *,
+ int inBH) = channel->impl->closeNtf;
+ void *closeNtfData = channel->impl->closeNtfData;
+
+ while (WriteTrylock(channel)) {
+ /* Take the write lock; kick writers out if necessary. */
+
+ CommOS_Debug(("%s: Kicking writers out...\n", __FUNCTION__));
+ CommOS_WakeUp(&channel->availableWaitQ);
+ }
+ WriteUnlock(channel);
+
+ CommOS_Debug(("%s: Nuking zombie channel.\n", __FUNCTION__));
+ CommClose(channel);
+ if (closeNtf) {
+ closeNtf(closeNtfData, &transpArgs, 0);
+ }
+ rc = -1;
+ } else if (CommIsInitialized(channel) &&
+ (channel->impl->openAtMillis <=
+ CommOS_GetCurrentMillis())) {
+ if (!CommOpen(channel)) {
+ if (channel->transpArgs.mode == COMM_TRANSP_INIT_CREATE) {
+ /*
+ * If the attach side doesn't get notified, the entry will
+ * time out in OPENED and will be collected.
+ * Note that during the CommOpen(Transp_Open) call, the IDs
+ * in the transpArgs may have changed. Use those.
+ */
+
+ CommTransp_Notify(&channel->impl->ntfCenterID,
+ &channel->transpArgs);
+ } else { /* Attach mode */
+ packet.len = sizeof packet;
+ packet.opCode = 0xff;
+ packet.flags = 0x00;
+
+ /*
+ * Send out control packet, attach ack, and transition straight
+ * to ACTIVE.
+ */
+
+ rc = CommTransp_EnqueueAtomic(channel->transp,
+ &packet, sizeof packet);
+ if (rc == sizeof packet) {
+ /* Guard against potentially concurrent zombify. */
+
+ CommGlobalLockBH();
+ if (CommIsOpened(channel)) {
+ CommOS_Debug(("%s: Sent attach ack. Activating channel.\n",
+ __FUNCTION__));
+ CommSetActive(channel);
+ }
+ CommGlobalUnlockBH();
+ }
+ }
+ rc = 1;
+ }
+ } else if (CommIsOpened(channel) &&
+ (channel->transpArgs.mode == COMM_TRANSP_INIT_CREATE)) {
+ /*
+ * Get control packet (opCode == 0xff), attach ack (flags == 0x0),
+ * or check whether the channel timed out in OPENED.
+ */
+
+ rc = CommTransp_DequeueAtomic(channel->transp,
+ &packet, sizeof packet);
+ if (rc == sizeof packet) {
+ void (*activateNtf)(void *activateNtfData, CommChannel) = NULL;
+ void *activateNtfData = NULL;
+
+ /* Guard against potentially concurrent zombify. */
+
+ CommGlobalLockBH();
+ if (CommIsOpened(channel) &&
+ (packet.opCode == 0xff) && (packet.flags == 0x0)) {
+ activateNtf = channel->impl->activateNtf;
+ activateNtfData = channel->impl->activateNtfData;
+
+ CommSetActive(channel);
+ CommOS_Debug(("%s: Received attach ack. Activating channel.\n",
+ __FUNCTION__));
+ }
+ CommHold(channel);
+ CommGlobalUnlockBH();
+
+ if (activateNtf) {
+ /* The callback must be short and 'put' the channel when done. */
+
+ activateNtf(activateNtfData, channel);
+ } else {
+ /* Don't forget to put back the channel if no activate callback. */
+
+ CommRelease(channel);
+ }
+ } else if ((channel->impl->openTimeoutAtMillis <=
+ CommOS_GetCurrentMillis()) ||
+ !running) {
+ zombify = 1;
+ CommOS_Debug(("%s: Zombifying expired opened channel.\n",
+ __FUNCTION__));
+ }
+ rc = 1;
+ }
+ DispatchUnlock(channel);
+
+out:
+ if (zombify) {
+ Comm_Zombify(channel, 0);
+ }
+ return rc;
+
+outUnlockAndFreeIovec:
+ DispatchUnlock(channel);
+ for ( ; vecLen; ) {
+ if (vec[--vecLen].iov_base) {
+ channel->impl->dataFree(vec[vecLen].iov_base);
+ vec[vecLen].iov_base = NULL;
+ }
+ vec[vecLen].iov_len = 0;
+ }
+ goto out;
+#undef VEC_SIZE
+}
+
+
+/**
+ * @brief Main input processing function operating on all channels.
+ * @return number of processed channels.
+ * @sideeffects Lifecycle states are transitioned to and from. Channels may
+ * be opened and destroyed, waiting writers may be woken up, and input
+ * may be handed off to operation callbacks.
+ */
+
+unsigned int
+Comm_DispatchAll(void)
+{
+ unsigned int i;
+ unsigned int hits;
+
+ for (hits = 0, i = 0; running && (i < commChannelSize); i++) {
+ hits += !!Comm_Dispatch(&commChannels[i]);
+ }
+ return hits;
+}
+
+
+/**
+ * @brief Writes a fully formatted packet (containing payload data, if
+ * applicable) to the specified channel.
+ *
+ * The operation may block until enough write space is available, but no
+ * more than the specified interval. The operation either writes the full
+ * amount of bytes, or it fails. Warning: callers must _not_ use the
+ * _Lock/_Unlock functions to bracket calls to this function.
+ * @param[in,out] channel channel to write to.
+ * @param packet packet to write.
+ * @param[in,out] timeoutMillis interval in milliseconds to wait.
+ * @return number of bytes written, 0 if it times out, -1 error.
+ * @sideeffects Data may be written to the channel.
+ */
+
+int
+Comm_Write(CommChannel channel,
+ const CommPacket *packet,
+ unsigned long long *timeoutMillis)
+{
+ int rc = -1;
+ int zombify;
+
+ if (!channel || !timeoutMillis ||
+ !packet || (packet->len < sizeof *packet)) {
+ return rc;
+ }
+
+ zombify = (*timeoutMillis >= COMM_MAX_TO);
+
+ WriteLock(channel);
+ if (!CommIsActive(channel)) {
+ goto out;
+ }
+
+ CommTransp_EnqueueReset(channel->transp);
+ channel->desiredWriteSpace = packet->len;
+ rc = CommOS_DoWait(&channel->availableWaitQ, WriteSpaceCondition,
+ channel, NULL, timeoutMillis,
+ (*timeoutMillis != COMM_MAX_TO_UNINT));
+ channel->desiredWriteSpace = -1U;
+
+ if (rc) { /* Don't zombify, if it didn't time out. */
+ zombify = 0;
+ }
+ if (rc == 1) { /* Enough write space, enqueue the packet. */
+ rc = CommTransp_EnqueueAtomic(channel->transp, packet, packet->len);
+ if (rc != packet->len) {
+ zombify = 1;
+ rc = -1; /* Fatal protocol error. */
+ }
+ }
+
+out:
+ WriteUnlock(channel);
+ if (zombify) {
+ Comm_Zombify(channel, 0);
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Writes a packet and associated payload data to the specified channel.
+ * The operation may block until enough write space is available, but
+ * not more than the specified interval.
+ * The operation either writes the full amount of bytes, or it fails.
+ * If there is not enough data in the vector, padding will be added to
+ * reach the specified packet length, if the flags parameter requires it.
+ * Users may call this function successively to write several packets
+ * from large {io|k}vecs, when the flags parameter indicates it. If this
+ * is the case, the packet header needs to be updated accordingly in
+ * between calls, for the different (total) lengths.
+ * Warning: callers must _not_ use the _Lock/_Unlock functions to bracket
+ * calls to this function.
+ * @param[in,out] channel the specified channel.
+ * @param packet packet to write.
+ * @param[in,out] vec kvec to write from.
+ * @param[in,out] vecLen length of kvec.
+ * @param[in,out] timeoutMillis interval in milliseconds to wait.
+ * @param[in,out] iovOffset must be set to 0 before first call (internal cookie)
+ * @return number of bytes written, 0 if it timed out, -1 error.
+ * @sideeffects data may be written to the channel.
+ */
+
+int
+Comm_WriteVec(CommChannel channel,
+ const CommPacket *packet,
+ struct kvec **vec,
+ unsigned int *vecLen,
+ unsigned long long *timeoutMillis,
+ unsigned int *iovOffset)
+{
+ int rc;
+ int zombify;
+ unsigned int dataLen;
+ unsigned int vecDataLen;
+ unsigned int vecNdx;
+ unsigned int iovLen;
+ void *iovBase;
+
+ if (!channel || !timeoutMillis || !iovOffset ||
+ !packet || (packet->len < sizeof *packet) ||
+ (((dataLen = packet->len - sizeof *packet) > 0) &&
+ (!*vec || !*vecLen))) {
+ return -1;
+ }
+
+ zombify = (*timeoutMillis >= COMM_MAX_TO);
+
+ WriteLock(channel);
+ if (!CommIsActive(channel)) {
+ rc = -1;
+ goto out;
+ }
+
+ CommTransp_EnqueueReset(channel->transp);
+ channel->desiredWriteSpace = packet->len;
+ rc = CommOS_DoWait(&channel->availableWaitQ, WriteSpaceCondition,
+ channel, NULL, timeoutMillis,
+ (*timeoutMillis != COMM_MAX_TO_UNINT));
+ channel->desiredWriteSpace = -1U;
+
+ if (rc) { /* Don't zombify, if it didn't time out. */
+ zombify = 0;
+ }
+ if (rc == 1) { /* Enough write space, enqueue the packet. */
+ iovLen = 0;
+ rc = CommTransp_EnqueueSegment(channel->transp, packet, sizeof *packet);
+ if (rc != sizeof *packet) {
+ zombify = 1;
+ rc = -1; /* Fatal protocol error. */
+ goto out;
+ }
+
+ if (dataLen > 0) {
+ int done = 0;
+
+ for (vecDataLen = 0, vecNdx = 0; vecNdx < *vecLen; vecNdx++) {
+ if (vecNdx) {
+ *iovOffset = 0;
+ }
+ iovLen = (*vec)[vecNdx].iov_len - *iovOffset;
+ iovBase = (*vec)[vecNdx].iov_base + *iovOffset;
+
+ if (!iovLen) {
+ continue;
+ }
+
+ vecDataLen += iovLen;
+ if (vecDataLen >= dataLen) {
+ iovLen -= (vecDataLen - dataLen);
+ done = 1;
+ }
+
+ rc = CommTransp_EnqueueSegment(channel->transp, iovBase, iovLen);
+ if (rc != iovLen) {
+ zombify = 1;
+ rc = -1; /* Fatal protocol error, close down comm. */
+ goto out;
+ }
+
+ if (done) {
+ CommTransp_EnqueueCommit(channel->transp);
+ if (vecDataLen == dataLen) {
+ vecNdx++;
+ *iovOffset = 0;
+ } else {
+ *iovOffset += iovLen;
+ }
+ *vecLen -= vecNdx;
+ *vec += vecNdx;
+ break;
+ }
+ }
+
+ if (!done) {
+ /*
+ * We exhausted all the bytes in the given vector, but total length
+ * in the packet header is more than we sent (was available).
+ * If so, we pad by sending zero bytes to reach length required.
+ */
+
+ static char pad[1024];
+ unsigned int delta;
+ unsigned int toSend;
+
+ while (vecDataLen < dataLen) {
+ delta = dataLen - vecDataLen;
+ toSend = delta <= sizeof pad ? delta : sizeof pad;
+ if (toSend == delta) {
+ done = 1;
+ }
+ vecDataLen += toSend;
+
+ rc = CommTransp_EnqueueSegment(channel->transp, pad, toSend);
+ if (rc != toSend) {
+ zombify = 1;
+ rc = -1; /* Fatal protocol error, close down comm. */
+ goto out;
+ }
+
+ if (done) {
+ CommTransp_EnqueueCommit(channel->transp);
+ *vec = NULL;
+ *vecLen = 0;
+ *iovOffset = 0;
+ break;
+ }
+ }
+ }
+ } else {
+ CommTransp_EnqueueCommit(channel->transp);
+ }
+ rc = (int)packet->len;
+ } else {
+ CommOS_Debug(("%s: timed out...\n", __FUNCTION__));
+ }
+
+out:
+ WriteUnlock(channel);
+ if (zombify) {
+ Comm_Zombify(channel, 0);
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Releases channel ref count. This function is exported for the upper
+ * layer's 'activateNtf' callback which may be run asynchronously. The
+ * callback is protected from concurrent channel releases until it calls
+ * this function.
+ * @param[in,out] channel CommChannel structure to release.
+ */
+
+void
+Comm_Put(CommChannel channel)
+{
+ if (channel) {
+ CommRelease(channel);
+ }
+}
+
+
+/**
+ * @brief Uses the read lock. This function is exported for the upper layer
+ * such that it can order acquisition of a different lock (socket) with
+ * the release of the dispatch lock.
+ * @param[in,out] channel CommChannel structure to unlock.
+ */
+
+void
+Comm_DispatchUnlock(CommChannel channel)
+{
+ if (channel) {
+ DispatchUnlock(channel);
+ }
+}
+
+
+/**
+ * @brief Lock the channel for upper layer state.
+ * This function is exported for the upper layer to ensure that channel
+ * isn't closed while updating the layer state. Operations using this
+ * function are expected to be short, since unlike the _Write functions,
+ * these callers cannot be signaled.
+ * @param[in,out] channel CommChannel structure to lock.
+ * @return zero if successful, -1 otherwise.
+ */
+
+int
+Comm_Lock(CommChannel channel)
+{
+ if (!channel) {
+ return -1;
+ }
+ StateLock(channel);
+ if (!CommIsActive(channel) && !CommIsZombie(channel)) {
+ StateUnlock(channel);
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * @brief Uses the writer lock. This function is exported for the upper layer
+ * to ensure that channel isn't closed while updating the layer state.
+ * See Comm_Lock for details).
+ * @param[in,out] channel CommChannel structure to unlock.
+ */
+
+void
+Comm_Unlock(CommChannel channel)
+{
+ if (channel) {
+ StateUnlock(channel);
+ }
+}
+
+
+/**
+ * @brief Requests events be posted in-line after the function completes.
+ * @param channel channel object.
+ * @return current number of requests for inline event posting, or -1 on error.
+ */
+
+unsigned int
+Comm_RequestInlineEvents(CommChannel channel)
+{
+ if (channel->transp) {
+ return CommTransp_RequestInlineEvents(channel->transp);
+ } else {
+ return (unsigned int)-1;
+ }
+}
+
+
+/**
+ * @brief Requests events be posted out-of-band after the function completes.
+ * @param channel channel object.
+ * @return current number of requests for inline event posting, or -1 on error.
+ */
+
+unsigned int
+Comm_ReleaseInlineEvents(CommChannel channel)
+{
+ if (channel->transp) {
+ return CommTransp_ReleaseInlineEvents(channel->transp);
+ } else {
+ return (unsigned int)-1;
+ }
+}
diff --git a/arch/arm/mvp/commkm/comm.h b/arch/arm/mvp/commkm/comm.h
new file mode 100644
index 0000000..8291ae4
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm.h
@@ -0,0 +1,171 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Communication functions based on queue pair transport APIs.
+ *
+ * Comm is a shared memory-based mechanism that facilitates the implementation
+ * of kernel components that require host-to-guest, or guest-to-guest
+ * communication.
+ * This facility assumes the availability of a minimal shared memory queue pair
+ * implementation, such as MVP queue pairs or VMCI queue pairs. The latter must
+ * provide primitives for queue pair creation and destruction, and reading and
+ * writing from/to queue pairs.
+ * Comm assumes that the queue pair (transport) layer is not concerned with
+ * multi-threading, locking or flow control, and does not require such features.
+ */
+
+#ifndef _COMM_H_
+#define _COMM_H_
+
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#include "comm_os.h"
+#include "comm_transp.h"
+
+
+/* Default/maximum Comm timeouts (in milliseconds). */
+#define COMM_MAX_TO 60000ULL
+#define COMM_MAX_TO_UNINT (COMM_MAX_TO + 1)
+
+#define COMM_OPF_SET_ERR(flags) ((flags) |= 128)
+#define COMM_OPF_CLEAR_ERR(flags) ((flags) &= 127)
+#define COMM_OPF_TEST_ERR(flags) ((flags) & 128)
+
+#define COMM_OPF_SET_VAL(flags, val) ((flags) |= ((val) & 127))
+#define COMM_OPF_GET_VAL(flags) ((flags) & 127)
+
+/**
+ * Packet (header) structure.
+ * NB: Do not change this structure, especially the first three fields; there
+ * will be consequences. It may be extended, but it's not recommended: all
+ * operations carry this header, so it's better kept in its minimal form.
+ */
+
+typedef struct CommPacket {
+ unsigned int len; // Total length
+ unsigned char flags; // Operation flags
+ unsigned char opCode; // Operation to call
+ unsigned short data16; // Auxiliary data
+ unsigned long long data64;
+ unsigned long long data64ex;
+ union {
+ struct {
+ unsigned int data32;
+ unsigned int data32ex;
+ };
+ unsigned long long data64ex2;
+ };
+} CommPacket;
+
+
+/* Opaque structure representing a communication channel. */
+
+struct CommChannelPriv;
+typedef struct CommChannelPriv *CommChannel;
+
+
+/* Input operations associated with a comm channel. */
+
+typedef void (*CommOperationFunc)(CommChannel channel,
+ void *state,
+ CommPacket *packet,
+ struct kvec *vec,
+ unsigned int vecLen);
+
+
+/* Helper macros */
+
+#define COMM_DEFINE_OP(funcName) \
+void \
+funcName(CommChannel channel, \
+ void *state, \
+ CommPacket *packet, \
+ struct kvec *vec, \
+ unsigned int vecLen)
+
+
+/* Comm-based implementations. */
+
+typedef struct CommImpl {
+ struct module *owner;
+ int (*checkArgs)(CommTranspInitArgs *transpArgs);
+ void *(*stateCtor)(CommChannel channel);
+ void (*stateDtor)(void *state);
+ void *(*dataAlloc)(unsigned int dataLen);
+ void (*dataFree)(void *data);
+ const CommOperationFunc *operations;
+ void (*closeNtf)(void *closeNtfData,
+ const CommTranspInitArgs *transpArgs,
+ int inBH);
+ void *closeNtfData;
+ void (*activateNtf)(void *activateNtfData,
+ CommChannel channel);
+ void *activateNtfData;
+ unsigned long long openAtMillis;
+ unsigned long long openTimeoutAtMillis;
+ CommTranspID ntfCenterID;
+} CommImpl;
+
+
+int Comm_Init(unsigned int maxChannels);
+int Comm_Finish(unsigned long long *timeoutMillis);
+int Comm_RegisterImpl(const CommImpl *impl);
+void Comm_UnregisterImpl(const CommImpl *impl);
+int Comm_IsActive(CommChannel channel);
+CommTranspInitArgs Comm_GetTranspInitArgs(CommChannel channel);
+void *Comm_GetState(CommChannel channel);
+int Comm_Dispatch(CommChannel channel);
+unsigned int Comm_DispatchAll(void);
+void Comm_Put(CommChannel channel);
+void Comm_DispatchUnlock(CommChannel channel);
+int Comm_Lock(CommChannel channel);
+void Comm_Unlock(CommChannel channel);
+int Comm_Zombify(CommChannel channel, int inBH);
+
+int
+Comm_Alloc(const CommTranspInitArgs *transpArgs,
+ const CommImpl *impl,
+ int inBH,
+ CommChannel *newChannel);
+
+
+int
+Comm_Write(CommChannel channel,
+ const CommPacket *packet,
+ unsigned long long *timeoutMillis);
+
+int
+Comm_WriteVec(CommChannel channel,
+ const CommPacket *packet,
+ struct kvec **vec,
+ unsigned int *vecLen,
+ unsigned long long *timeoutMillis,
+ unsigned int *iovOffset);
+
+unsigned int Comm_RequestInlineEvents(CommChannel channel);
+unsigned int Comm_ReleaseInlineEvents(CommChannel channel);
+
+#endif // _COMM_H_
diff --git a/arch/arm/mvp/commkm/comm_ev.h b/arch/arm/mvp/commkm/comm_ev.h
new file mode 100644
index 0000000..bf629c3
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_ev.h
@@ -0,0 +1,51 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief various comm event signaling types and signatures
+ */
+
+#ifndef _COMM_EV_H
+#define _COMM_EV_H
+
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_GPL
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_MODULE
+#include "include_check.h"
+
+/**
+ * @name Identifiers of comm event signaling class methods
+ * @{
+ */
+#define MVP_COMM_EV_SIGNATURE 0x4d4d4f43 ///< 'COMM'
+#define MVP_COMM_EV_SIGNAL (MVP_OBJECT_CUSTOM_BASE + 0) ///< Signal host
+#define MVP_COMM_EV_READ_EVENT_DATA (MVP_OBJECT_CUSTOM_BASE + 1) ///< read event data
+#define MVP_COMM_EV_LAST (MVP_OBJECT_CUSTOM_BASE + 2) ///< Number of methods
+/**@}*/
+
+typedef struct CommEvent {
+ CommTranspID id;
+ CommTranspIOEvent event;
+} CommEvent;
+
+#endif
diff --git a/arch/arm/mvp/commkm/comm_ev_kernel.c b/arch/arm/mvp/commkm/comm_ev_kernel.c
new file mode 100644
index 0000000..0701945
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_ev_kernel.c
@@ -0,0 +1,136 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Comm event signaling, host kernel side.
+ */
+
+#include <linux/net.h>
+
+#include "mvp_types.h"
+#include "comm_os.h"
+#include "comm_transp_impl.h"
+#include "mksck_sockaddr.h"
+#include "comm_ev.h"
+#include "mvpkm_comm_ev.h"
+
+static struct socket *sock;
+
+/**
+ * @brief Raises a transport event on the provided event ID (address). This
+ * function is called from a comm_transp provider, such as comm_transp_mvp,
+ * when it needs to signal an event on a given channel.
+ * @param targetEvID opaque event channel ID (interpreted by implementation).
+ * @param transpID ID of transport to signal.
+ * @param eventType event type to raise.
+ * @return 0 if successful, -1 otherwise.
+ */
+
+int
+CommTranspEvent_Raise(unsigned int targetEvID, // unused
+ CommTranspID *transpID,
+ CommTranspIOEvent eventType)
+{
+ struct sockaddr_mk guestAddr;
+ struct msghdr msg;
+ struct kvec vec[1];
+ int rc;
+ CommEvent event;
+
+ if (!transpID) {
+ return -1;
+ }
+
+ guestAddr.mk_family = AF_MKSCK;
+ guestAddr.mk_addr.addr = Mksck_AddrInit(transpID->d32[0], MKSCK_PORT_COMM_EV);
+
+ memset(&msg, 0, sizeof (struct msghdr));
+ msg.msg_name = &guestAddr;
+ msg.msg_namelen = sizeof (guestAddr);
+
+ event.id = *transpID;
+ event.event = eventType;
+
+ vec[0].iov_base = &event;
+ vec[0].iov_len = sizeof (CommEvent);
+
+ rc = kernel_sendmsg(sock,
+ &msg,
+ vec,
+ 1,
+ sizeof (CommEvent));
+ rc = (rc < 0) ? -1 : 0;
+ return rc;
+}
+
+
+/**
+ * @brief Performs one-time, global initialization of event provider.
+ * @return 0 if successful, -1 otherwise.
+ */
+int
+CommTranspEvent_Init(void)
+{
+ struct sockaddr_mk addr = { AF_MKSCK, { .addr = MKSCK_ADDR_UNDEF } };
+ int rc;
+
+ rc = sock_create_kern(AF_MKSCK, SOCK_DGRAM, 0, &sock);
+ if (rc < 0) {
+ goto out;
+ }
+
+ rc = kernel_bind(sock, (struct sockaddr *) &addr, sizeof addr);
+ if (rc < 0) {
+ sock_release(sock);
+ sock = NULL;
+ goto out;
+ }
+
+ Mvpkm_CommEvRegisterProcessCB(CommTranspEvent_Process);
+
+out:
+ if (rc) {
+ CommOS_Log(("%s: Failed to initialize transport event signaling\n",
+ __FUNCTION__));
+ } else {
+ CommOS_Log(("%s: Transport event signaling initialization successful\n",
+ __FUNCTION__));
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Performs global clean-up of event provider.
+ */
+
+void
+CommTranspEvent_Exit(void)
+{
+ Mvpkm_CommEvUnregisterProcessCB();
+ if (sock) {
+ sock_release(sock);
+ sock = NULL;
+ }
+
+ CommOS_Debug(("%s: done.\n", __FUNCTION__));
+}
diff --git a/arch/arm/mvp/commkm/comm_os.h b/arch/arm/mvp/commkm/comm_os.h
new file mode 100644
index 0000000..f98c8d4
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_os.h
@@ -0,0 +1,150 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Cross-platform base type definitions and function declarations.
+ * Includes OS-specific base type definitions and function declarations.
+ */
+
+#ifndef _COMM_OS_H_
+#define _COMM_OS_H_
+
+/* For-ever timeout constant (in milliseconds). */
+#define COMM_OS_4EVER_TO ((unsigned long long)(~0UL >> 1))
+
+/* Condition function prototype. Returns 1: true, 0: false, < 0: error code. */
+typedef int (*CommOSWaitConditionFunc)(void *arg1, void *arg2);
+
+/* Dispatch function prototype. Called by input (dispatch) kernel threads. */
+typedef unsigned int (*CommOSDispatchFunc)(void);
+
+/* Module initialization and exit callback functions. */
+extern int (*commOSModInit)(void *args);
+extern void (*commOSModExit)(void);
+
+/* Macro to assign Init and Exit callbacks. */
+#define COMM_OS_MOD_INIT(init, exit) \
+ int (*commOSModInit)(void *args) = init; \
+ void (*commOSModExit)(void) = exit
+
+
+/*
+ * OS-specific implementations must provide the following:
+ * 1. Types:
+ * CommOSAtomic
+ * CommOSSpinlock
+ * CommOSMutex
+ * CommOSWaitQueue
+ * CommOSWork
+ * CommOSWorkFunc
+ * CommOSList
+ * CommOSModule
+ * struct kvec
+ *
+ * 2. Definition, initializers:
+ * CommOSSpinlock_Define()
+ *
+ * 3. Functions:
+ * void CommOS_Debug(const char *format, ...);
+ * void CommOS_Log(const char *format, ...);
+ * void CommOS_WriteAtomic(CommOSAtomic *atomic, int val);
+ * int CommOS_ReadAtomic(CommOSAtomic *atomic);
+ * int CommOS_AddReturnAtomic(CommOSAtomic *atomic, int val);
+ * int CommOS_SubReturnAtomic(CommOSAtomic *atomic, int val);
+ * void CommOS_SpinlockInit(CommOSSpinlock *lock);
+ * void CommOS_SpinLockBH(CommOSSpinlock *lock);
+ * int CommOS_SpinTrylockBH(CommOSSpinlock *lock);
+ * void CommOS_SpinUnlockBH(CommOSSpinlock *lock);
+ * void CommOS_SpinLock(CommOSSpinlock *lock);
+ * int CommOS_SpinTrylock(CommOSSpinlock *lock);
+ * void CommOS_SpinUnlock(CommOSSpinlock *lock);
+ * void CommOS_MutexInit(CommOSMutex *mutex);
+ * void CommOS_MutexLock(CommOSMutex *mutex);
+ * int CommOS_MutexLockUninterruptible(CommOSMutex *mutex);
+ * int CommOS_MutexTrylock(CommOSMutex *mutex);
+ * void CommOS_MutexUnlock(CommOSMutex *mutex);
+ * void CommOS_WaitQueueInit(CommOSWaitQueue *wq);
+ * CommOS_DoWait(CommOSWaitQueue *wq,
+ * CommOSWaitConditionFunc cond,
+ * void *condArg1,
+ * void *condArg2,
+ * unsigned long long *timeoutMillis,
+ * int interruptible);
+ * int CommOS_Wait(CommOSWaitQueue *wq,
+ * CommOSWaitConditionFunc func,
+ * void *funcArg1,
+ * void *funcArg2,
+ * unsigned long long *timeoutMillis);
+ * int CommOS_WaitUninterruptible(CommOSWaitQueue *wq,
+ * CommOSWaitConditionFunc func,
+ * void *funcArg1,
+ * void *funcArg2,
+ * unsigned long long *timeoutMillis);
+ * void CommOS_WakeUp(CommOSWaitQueue *wq);
+ * void *CommOS_KmallocNoSleep(unsigned int size);
+ * void *CommOS_Kmalloc(unsigned int size);
+ * void CommOS_Kfree(void *arg);
+ * void CommOS_Yield(void);
+ * unsigned long long CommOS_GetCurrentMillis(void);
+ * void CommOS_ListInit(CommOSList *list);
+ * int CommOS_ListEmpty(CommOSList *list);
+ * void CommOS_ListAdd(CommOSList *list, CommOSList *listElem);
+ * void CommOS_ListAddTail(CommOSList *list, CommOSList *listElem);
+ * void int CommOS_ListDel(CommOSList *listElem);
+ * Macros:
+ * CommOS_ListForEach(*list, *item, itemListFieldName);
+ * CommOS_ListForEachSafe(*list, *item, *tmp, itemListFieldName);
+ * void CommOS_ListSplice(CommOSList *list, CommOSList *listToAdd);
+ * void CommOS_ListSpliceTail(CommOSList *list, CommOSList *listToAdd);
+ * CommOSModule CommOS_ModuleSelf(void);
+ * int CommOS_ModuleGet(CommOSModule module);
+ * void CommOS_ModulePut(CommOSModule module);
+ * void CommOS_MemBarrier(void);
+ *
+ * These cannot be defined here: a) non-pointer type definitions need size
+ * information, and b) functions may or may not be inlined, or macros may
+ * be used instead.
+ */
+
+
+#ifdef __linux__
+#include "comm_os_linux.h"
+#else
+#error "Unsupported OS"
+#endif
+
+/* Functions to start and stop the dispatch and aio kernel threads. */
+void CommOS_StopIO(void);
+void CommOS_ScheduleDisp(void);
+void CommOS_InitWork(CommOSWork *work, CommOSWorkFunc func);
+int CommOS_ScheduleAIOWork(CommOSWork *work);
+void CommOS_FlushAIOWork(CommOSWork *work);
+
+int
+CommOS_StartIO(const char *dispatchTaskName,
+ CommOSDispatchFunc dispatchHandler,
+ unsigned int interval,
+ unsigned int maxCycles,
+ const char *aioTaskName);
+
+
+#endif /* _COMM_OS_H_ */
diff --git a/arch/arm/mvp/commkm/comm_os_linux.c b/arch/arm/mvp/commkm/comm_os_linux.c
new file mode 100644
index 0000000..74f99f5
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_os_linux.c
@@ -0,0 +1,371 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Linux-specific functions/types.
+ */
+
+#include "comm_os.h"
+
+#define DISPATCH_MAX_CYCLES 8192
+
+/* Type definitions */
+
+typedef struct workqueue_struct CommOSWorkQueue;
+
+
+/* Static data */
+
+static volatile int running;
+static int numCpus;
+static CommOSWorkQueue *dispatchWQ;
+static CommOSDispatchFunc dispatch;
+static CommOSWork dispatchWorksNow[NR_CPUS];
+static CommOSWork dispatchWorks[NR_CPUS];
+static unsigned int dispatchInterval = 1;
+static unsigned int dispatchMaxCycles = 2048;
+static CommOSWorkQueue *aioWQ;
+
+
+/**
+ * @brief Initializes a workqueue consisting of per-cpu kernel threads.
+ * @param name workqueue name
+ * @return workqueue handle if successful, NULL otherwise
+ */
+
+static inline CommOSWorkQueue *
+CreateWorkqueue(const char *name)
+{
+ return create_workqueue(name);
+}
+
+
+/**
+ * @brief Destroys a workqueue and stops its threads.
+ * @param[in,out] wq workqueue to destroy.
+ * @return workqueue handle is successful, NULL otherwise.
+ */
+
+static inline void
+DestroyWorkqueue(CommOSWorkQueue *wq)
+{
+ destroy_workqueue(wq);
+}
+
+
+/**
+ * @brief Force execution of a work item.
+ * @param[in,out] work work item to dequeue.
+ */
+
+static inline void
+FlushDelayedWork(CommOSWork *work)
+{
+ flush_delayed_work(work);
+}
+
+
+/**
+ * @brief Enqueue a work item to a workqueue for execution on a given cpu
+ * and after the specified interval.
+ * @param cpu cpu number. If negative, work item is enqueued on current cpu.
+ * @param[in,out] wq target work queue.
+ * @param[in,out] work work item to enqueue.
+ * @param jif delay interval.
+ * @return zero if successful, non-zero otherwise.
+ */
+
+static inline int
+QueueDelayedWorkOn(int cpu,
+ CommOSWorkQueue *wq,
+ CommOSWork *work,
+ unsigned long jif)
+{
+ if (cpu < 0) {
+ return !queue_delayed_work(wq, work, jif) ? -1 : 0;
+ } else {
+ return !queue_delayed_work_on(cpu, wq, work, jif) ? -1 : 0;
+ }
+}
+
+
+/**
+ * @brief Enqueues a work item to a workqueue for execution on the current cpu
+ * and after the specified interval.
+ * @param[in,out] wq target work queue.
+ * @param[in,out] work work item to enqueue.
+ * @param jif delay interval.
+ * @return zero if successful, non-zero otherwise.
+ */
+
+static inline int
+QueueDelayedWork(CommOSWorkQueue *wq,
+ CommOSWork *work,
+ unsigned long jif)
+{
+ return QueueDelayedWorkOn(-1, wq, work, jif);
+}
+
+
+/**
+ * @brief Cancels a queued delayed work item and synchronizes with its
+ * completion.
+ * @param[in,out] work work item to cancel
+ */
+
+static inline void
+WaitForDelayedWork(CommOSWork *work)
+{
+ cancel_delayed_work_sync(work);
+}
+
+
+/**
+ * @brief Discards work items queued to the specified workqueue.
+ * @param[in,out] wq work queue to flush.
+ */
+
+static inline void
+FlushWorkqueue(CommOSWorkQueue *wq)
+{
+ flush_workqueue(wq);
+}
+
+
+/**
+ * @brief Schedules dispatcher threads for immediate execution.
+ */
+
+void
+CommOS_ScheduleDisp(void)
+{
+ CommOSWork *work = &dispatchWorksNow[get_cpu()];
+
+ put_cpu();
+ if (running) {
+ QueueDelayedWork(dispatchWQ, work, 0);
+ }
+}
+
+
+/**
+ * @brief Default delayed work callback function implementation.
+ * Calls the input function specified at initialization.
+ * @param[in,out] work work item.
+ */
+
+static void
+DispatchWrapper(CommOSWork *work)
+{
+ unsigned int misses;
+
+ for (misses = 0; running && (misses < dispatchMaxCycles); ) {
+ /* We run for at most dispatchMaxCycles worth of channel no-ops. */
+
+ if (!dispatch()) {
+ /* No useful work was done, on any of the channels. */
+
+ misses++;
+ if ((misses % 32) == 0) {
+ CommOS_Yield();
+ }
+ } else {
+ misses = 0;
+ }
+ }
+
+ if (running &&
+ (work >= &dispatchWorks[0]) &&
+ (work <= &dispatchWorks[NR_CPUS - 1])) {
+ /*
+ * If still running _and_ this was a regular, time-based run, then
+ * re-arm the timer.
+ */
+
+ QueueDelayedWork(dispatchWQ, work, dispatchInterval);
+ }
+}
+
+
+/**
+ * @brief Initializes work item with specified callback function.
+ * @param[in,out] work work queue to initialize.
+ * @param func work item to initialize the queue with.
+ */
+
+void
+CommOS_InitWork(CommOSWork *work,
+ CommOSWorkFunc func)
+{
+ INIT_DELAYED_WORK(work, (work_func_t)func);
+}
+
+
+/**
+ * @brief Flush execution of a work item
+ * @param{in,out] work work item to dequeue
+ */
+void
+CommOS_FlushAIOWork(CommOSWork *work)
+{
+ if (aioWQ && work) {
+ FlushDelayedWork(work);
+ }
+}
+
+
+/**
+ * @brief Queue a work item to the AIO workqueue.
+ * @param[in,out] work work item to enqueue.
+ * @return zero if work enqueued, non-zero otherwise.
+ */
+
+int
+CommOS_ScheduleAIOWork(CommOSWork *work)
+{
+ if (running && aioWQ && work) {
+ return QueueDelayedWork(aioWQ, work, 0);
+ }
+ return -1;
+}
+
+
+/**
+ * @brief Initializes the base IO system.
+ * @param dispatchTaskName dispatch thread(s) name.
+ * @param dispatchFunc dispatch function.
+ * @param intervalMillis periodic interval in milliseconds to call dispatch.
+ * The floor is 1 jiffy, regardless of how small intervalMillis is
+ * @param maxCycles number of cycles to do adaptive polling before scheduling.
+ * The maximum number of cycles is DISPATCH_MAX_CYCLES.
+ * @param aioTaskName AIO thread(s) name. If NULL, AIO threads aren't started.
+ * @return zero is successful, -1 otherwise.
+ * @sideeffects Dispatch threads, and if applicable, AIO threads are started.
+ */
+
+int
+CommOS_StartIO(const char *dispatchTaskName, // IN
+ CommOSDispatchFunc dispatchFunc, // IN
+ unsigned int intervalMillis, // IN
+ unsigned int maxCycles, // IN
+ const char *aioTaskName) // IN
+{
+ int rc;
+ int cpu;
+
+ if (running) {
+ CommOS_Debug(("%s: I/O tasks already running.\n", __FUNCTION__));
+ return 0;
+ }
+
+ /*
+ * OK, let's test the handler against NULL. Though, the whole concept
+ * of checking for NULL pointers, outside cases where NULL is meaningful
+ * to the implementation, is relatively useless: garbage, random pointers
+ * rarely happen to be all-zeros.
+ */
+
+ if (!dispatchFunc) {
+ CommOS_Log(("%s: a NULL Dispatch handler was passed.\n", __FUNCTION__));
+ return -1;
+ }
+ dispatch = dispatchFunc;
+
+ if (intervalMillis == 0) {
+ intervalMillis = 4;
+ }
+ if ((dispatchInterval = msecs_to_jiffies(intervalMillis)) < 1) {
+ dispatchInterval = 1;
+ }
+ if (maxCycles > DISPATCH_MAX_CYCLES) {
+ dispatchMaxCycles = DISPATCH_MAX_CYCLES;
+ } else if (maxCycles > 0) {
+ dispatchMaxCycles = maxCycles;
+ }
+ CommOS_Debug(("%s: Interval millis %u (jif:%u).\n", __FUNCTION__,
+ intervalMillis, dispatchInterval));
+ CommOS_Debug(("%s: Max cycles %u.\n", __FUNCTION__, dispatchMaxCycles));
+
+ numCpus = num_present_cpus();
+ dispatchWQ = CreateWorkqueue(dispatchTaskName);
+ if (!dispatchWQ) {
+ CommOS_Log(("%s: Couldn't create %s task(s).\n", __FUNCTION__,
+ dispatchTaskName));
+ return -1;
+ }
+
+ if (aioTaskName) {
+ aioWQ = CreateWorkqueue(aioTaskName);
+ if (!aioWQ) {
+ CommOS_Log(("%s: Couldn't create %s task(s).\n", __FUNCTION__,
+ aioTaskName));
+ DestroyWorkqueue(dispatchWQ);
+ return -1;
+ }
+ } else {
+ aioWQ = NULL;
+ }
+
+ running = 1;
+ for (cpu = 0; cpu < numCpus; cpu++) {
+ CommOS_InitWork(&dispatchWorksNow[cpu], DispatchWrapper);
+ CommOS_InitWork(&dispatchWorks[cpu], DispatchWrapper);
+ rc = QueueDelayedWorkOn(cpu, dispatchWQ,
+ &dispatchWorks[cpu],
+ dispatchInterval);
+ if (rc != 0) {
+ CommOS_StopIO();
+ return -1;
+ }
+ }
+ CommOS_Log(("%s: Created I/O task(s) successfully.\n", __FUNCTION__));
+ return 0;
+}
+
+
+/**
+ * @brief Stops the base IO system.
+ * @sideeffects Dispatch threads, and if applicable, AIO threads are stopped.
+ */
+
+void
+CommOS_StopIO(void)
+{
+ int cpu;
+
+ if (running) {
+ running = 0;
+ if (aioWQ) {
+ FlushWorkqueue(aioWQ);
+ DestroyWorkqueue(aioWQ);
+ aioWQ = NULL;
+ }
+ FlushWorkqueue(dispatchWQ);
+ for (cpu = 0; cpu < numCpus; cpu++) {
+ WaitForDelayedWork(&dispatchWorksNow[cpu]);
+ WaitForDelayedWork(&dispatchWorks[cpu]);
+ }
+ DestroyWorkqueue(dispatchWQ);
+ dispatchWQ = NULL;
+ CommOS_Log(("%s: I/O tasks stopped.\n", __FUNCTION__));
+ }
+}
diff --git a/arch/arm/mvp/commkm/comm_os_linux.h b/arch/arm/mvp/commkm/comm_os_linux.h
new file mode 100644
index 0000000..f92c8bd
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_os_linux.h
@@ -0,0 +1,699 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Contains linux-specific type definitions and function declarations
+ */
+
+#ifndef _COMM_OS_LINUX_H_
+#define _COMM_OS_LINUX_H_
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#error "Kernel versions lower than 2.6.20 are not supported"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+
+/*
+ * Type definitions.
+ */
+
+typedef atomic_t CommOSAtomic;
+typedef spinlock_t CommOSSpinlock;
+typedef struct mutex CommOSMutex;
+typedef wait_queue_head_t CommOSWaitQueue;
+typedef struct delayed_work CommOSWork;
+typedef void (*CommOSWorkFunc)(CommOSWork *work);
+typedef struct list_head CommOSList;
+typedef struct module *CommOSModule;
+
+
+/*
+ * Initializers.
+ */
+
+#define CommOSSpinlock_Define DEFINE_SPINLOCK
+
+
+#define COMM_OS_DOLOG(...) printk(KERN_INFO __VA_ARGS__)
+
+
+/**
+ * @brief Logs given arguments in debug builds.
+ */
+
+#if defined(COMM_OS_DEBUG)
+ #define CommOS_Debug(args) COMM_OS_DOLOG args
+#else
+ #define CommOS_Debug(args)
+#endif
+
+
+/**
+ * @brief Logs given arguments.
+ */
+
+#define CommOS_Log(args) COMM_OS_DOLOG args
+
+
+/**
+ * @brief Logs function name and location.
+ */
+
+#if defined(COMM_OS_TRACE)
+#define TRACE(ptr) \
+ do { \
+ CommOS_Debug(("%p:%s: at [%s:%d] with arg ptr [0x%p].\n", current, \
+ __FUNCTION__, __FILE__, __LINE__, (ptr))); \
+ } while (0)
+#else
+#define TRACE(ptr)
+#endif
+
+
+/**
+ * @brief Write atomic variable
+ * @param[in,out] atomic variable to write
+ * @param val new value
+ */
+
+static inline void
+CommOS_WriteAtomic(CommOSAtomic *atomic,
+ int val)
+{
+ atomic_set(atomic, val);
+}
+
+
+/**
+ * @brief Reads atomic variable
+ * @param atomic variable to read
+ * @return value
+ */
+
+static inline int
+CommOS_ReadAtomic(CommOSAtomic *atomic)
+{
+ return atomic_read(atomic);
+}
+
+
+/**
+ * @brief Atomically add value to atomic variable, return new value.
+ * @param[in,out] atomic variable
+ * @param val value to add
+ * @return new value
+ */
+
+static inline int
+CommOS_AddReturnAtomic(CommOSAtomic *atomic,
+ int val)
+{
+ return atomic_add_return(val, atomic);
+}
+
+
+/**
+ * @brief Atomically substract value from atomic variable, return new value.
+ * @param[in,out] atomic variable
+ * @param val value to substract
+ * @return new value
+ */
+
+static inline int
+CommOS_SubReturnAtomic(CommOSAtomic *atomic,
+ int val)
+{
+ return atomic_sub_return(val, atomic);
+}
+
+
+/**
+ * @brief Initializes a given lock.
+ * @param[in,out] lock lock to initialize
+ */
+
+static inline void
+CommOS_SpinlockInit(CommOSSpinlock *lock)
+{
+ spin_lock_init(lock);
+}
+
+
+/**
+ * @brief Locks given lock and disables bottom half processing.
+ * @param[in,out] lock lock to lock
+ */
+
+static inline void
+CommOS_SpinLockBH(CommOSSpinlock *lock)
+{
+ spin_lock_bh(lock);
+}
+
+
+/**
+ * @brief Attempts to lock the given lock and disable BH processing.
+ * @param[in,out] lock lock to lock
+ * @return zero if successful, non-zero otherwise
+ */
+
+static inline int
+CommOS_SpinTrylockBH(CommOSSpinlock *lock)
+{
+ return !spin_trylock_bh(lock);
+}
+
+
+/**
+ * @brief Unlocks given lock and re-enables BH processing.
+ * @param[in,out] lock lock to unlock
+ */
+
+static inline void
+CommOS_SpinUnlockBH(CommOSSpinlock *lock)
+{
+ spin_unlock_bh(lock);
+}
+
+
+/**
+ * @brief Locks the given lock.
+ * @param[in,out] lock lock to lock
+ */
+
+static inline void
+CommOS_SpinLock(CommOSSpinlock *lock)
+{
+ spin_lock(lock);
+}
+
+
+/**
+ * @brief Attempts to lock the given lock.
+ * @param[in,out] lock lock to try-lock
+ * @return zero if successful, non-zero otherwise
+ */
+
+static inline int
+CommOS_SpinTrylock(CommOSSpinlock *lock)
+{
+ return !spin_trylock(lock);
+}
+
+
+/**
+ * @brief Unlocks given lock.
+ * @param[in,out] lock lock to unlock
+ */
+
+static inline void
+CommOS_SpinUnlock(CommOSSpinlock *lock)
+{
+ spin_unlock(lock);
+}
+
+
+/**
+ * @brief Initializes given mutex.
+ * @param[in,out] mutex mutex to initialize
+ */
+
+static inline void
+CommOS_MutexInit(CommOSMutex *mutex)
+{
+ mutex_init(mutex);
+}
+
+
+/**
+ * @brief Acquires mutex.
+ * @param[in,out] mutex mutex to lock
+ * @return zero if successful, non-zero otherwise (interrupted)
+ */
+
+static inline int
+CommOS_MutexLock(CommOSMutex *mutex)
+{
+ return mutex_lock_interruptible(mutex);
+}
+
+
+/**
+ * @brief Acquires mutex in uninterruptible mode.
+ * @param[in,out] mutex mutex to lock
+ */
+
+static inline void
+CommOS_MutexLockUninterruptible(CommOSMutex *mutex)
+{
+ mutex_lock(mutex);
+}
+
+
+/**
+ * @brief Attempts to acquire given mutex.
+ * @param[in,out] mutex mutex to try-lock
+ * @return zero if successful, non-zero otherwise
+ */
+
+static inline int
+CommOS_MutexTrylock(CommOSMutex *mutex)
+{
+ return !mutex_trylock(mutex);
+}
+
+
+/**
+ * @brief Releases a given mutex.
+ * @param[in,out] mutex mutex to unlock
+ */
+
+static inline void
+CommOS_MutexUnlock(CommOSMutex *mutex)
+{
+ mutex_unlock(mutex);
+}
+
+
+/**
+ * @brief Initializes a wait queue.
+ * @param[in,out] wq workqueue to initialize
+ */
+
+static inline void
+CommOS_WaitQueueInit(CommOSWaitQueue *wq)
+{
+ init_waitqueue_head(wq);
+}
+
+
+/**
+ * @brief Puts the caller on a wait queue until either of the following occurs:
+ * - the condition function (predicate) evaluates to TRUE
+ * - the specified timeout interval elapsed
+ * - a signal is pending
+ * @param[in,out] wq wait queue to put item on
+ * @param cond predicate to test
+ * @param condArg1 argument 1 for cond
+ * @param condArg2 argument 2 for cond
+ * @param[in,out] timeoutMillis timeout interval in milliseconds
+ * @param interruptible enable/disable signal pending check
+ * @return 1 if condition was met
+ * 0 if the timeout interval elapsed
+ * <0, if a signal is pending or other error set by condition
+ * @sideeffect timeoutMillis is updated to time remaining
+ */
+
+static inline int
+CommOS_DoWait(CommOSWaitQueue *wq,
+ CommOSWaitConditionFunc cond,
+ void *condArg1,
+ void *condArg2,
+ unsigned long long *timeoutMillis,
+ int interruptible)
+{
+ int rc;
+ DEFINE_WAIT(wait);
+ long timeout;
+#if defined(COMM_OS_LINUX_WAIT_WORKAROUND)
+ long tmpTimeout;
+ long retTimeout;
+ const unsigned int interval = 50;
+#endif
+
+ if (!timeoutMillis) {
+ return -1;
+ }
+ if ((rc = cond(condArg1, condArg2)) != 0) {
+ return rc;
+ }
+
+#if defined(COMM_OS_LINUX_WAIT_WORKAROUND)
+ timeout = msecs_to_jiffies(interval < *timeoutMillis ?
+ interval : (unsigned int)*timeoutMillis);
+ retTimeout = msecs_to_jiffies((unsigned int)(*timeoutMillis));
+
+ for (; retTimeout >= 0; ) {
+ prepare_to_wait(wq, &wait,
+ (interruptible?TASK_INTERRUPTIBLE:TASK_UNINTERRUPTIBLE));
+ if ((rc = cond(condArg1, condArg2))) {
+ break;
+ }
+ if (interruptible && signal_pending(current)) {
+ rc = -EINTR;
+ break;
+ }
+ if ((tmpTimeout = schedule_timeout(timeout))) {
+ retTimeout -= (timeout - tmpTimeout);
+ } else {
+ retTimeout -= timeout;
+ }
+ if (retTimeout < 0) {
+ retTimeout = 0;
+ }
+ }
+ finish_wait(wq, &wait);
+ if (rc == 0) {
+ rc = cond(condArg1, condArg2);
+ if (rc && (retTimeout == 0)) {
+ retTimeout = 1;
+ }
+ }
+ *timeoutMillis = (unsigned long long)jiffies_to_msecs(retTimeout);
+#else // !defined(COMM_OS_LINUX_WAIT_WORKAROUND)
+ timeout = msecs_to_jiffies((unsigned int)(*timeoutMillis));
+
+ for (;;) {
+ prepare_to_wait(wq, &wait,
+ (interruptible?TASK_INTERRUPTIBLE:TASK_UNINTERRUPTIBLE));
+ if ((rc = cond(condArg1, condArg2)) != 0) {
+ break;
+ }
+ if (interruptible && signal_pending(current)) {
+ rc = -EINTR;
+ break;
+ }
+ if ((timeout = schedule_timeout(timeout)) == 0) {
+ rc = 0;
+ break;
+ }
+ }
+ finish_wait(wq, &wait);
+ if (rc == 0) {
+ rc = cond(condArg1, condArg2);
+ if (rc && (timeout == 0)) {
+ timeout = 1;
+ }
+ }
+ *timeoutMillis = (unsigned long long)jiffies_to_msecs(timeout);
+#endif
+
+ return rc;
+}
+
+
+/**
+ * @brief Puts the caller on a wait queue until either of the following occurs:
+ * - the condition function (predicate) evaluates to TRUE
+ * - the specified timeout interval elapsed
+ * - a signal is pending
+ * @param[in,out] wq wait queue to put item on
+ * @param cond predicate to test
+ * @param condArg1 argument 1 for cond
+ * @param condArg2 argument 2 for cond
+ * @param[in,out] timeoutMillis timeout interval in milliseconds
+ * @return 1 if condition was met
+ * 0 if the timeout interval elapsed
+ * <0, if a signal is pending or other error set by condition
+ * @sideeffect timeoutMillis is updated to time remaining
+ */
+
+static inline int
+CommOS_Wait(CommOSWaitQueue *wq,
+ CommOSWaitConditionFunc cond,
+ void *condArg1,
+ void *condArg2,
+ unsigned long long *timeoutMillis)
+{
+ return CommOS_DoWait(wq, cond, condArg1, condArg2, timeoutMillis, 1);
+}
+
+
+/**
+ * @brief Puts the caller on a wait queue until either of the following occurs:
+ * - the condition function (predicate) evaluates to TRUE
+ * - the specified timeout interval elapsed
+ * @param[in,out] wq wait queue to put item on
+ * @param cond predicate to test
+ * @param condArg1 argument 1 for cond
+ * @param condArg2 argument 2 for cond
+ * @param[in,out] timeoutMillis timeout interval in milliseconds
+ * @return 1 if condition was met
+ * 0 if the timeout interval elapsed
+ * <0, error set by condition
+ * @sideeffect timeoutMillis is updated to time remaining
+ */
+
+static inline int
+CommOS_WaitUninterruptible(CommOSWaitQueue *wq,
+ CommOSWaitConditionFunc cond,
+ void *condArg1,
+ void *condArg2,
+ unsigned long long *timeoutMillis)
+{
+ return CommOS_DoWait(wq, cond, condArg1, condArg2, timeoutMillis, 0);
+}
+
+
+/**
+ * @brief Wakes up task(s) waiting on the given wait queue.
+ * @param[in,out] wq wait queue.
+ */
+
+static inline void
+CommOS_WakeUp(CommOSWaitQueue *wq)
+{
+ wake_up(wq);
+}
+
+
+/**
+ * @brief Allocates kernel memory of specified size; does not sleep.
+ * @param size size to allocate.
+ * @return Address of allocated memory or NULL if the allocation fails.
+ */
+
+static inline void *
+CommOS_KmallocNoSleep(unsigned int size)
+{
+ return kmalloc(size, GFP_ATOMIC);
+}
+
+
+/**
+ * @brief Allocates kernel memory of specified size; may sleep.
+ * @param size size to allocate.
+ * @return Address of allocated memory or NULL if the allocation fails.
+ */
+
+static inline void *
+CommOS_Kmalloc(unsigned int size)
+{
+ return kmalloc(size, GFP_KERNEL);
+}
+
+
+/**
+ * @brief Frees previously allocated kernel memory.
+ * @param obj object to free.
+ */
+
+static inline void
+CommOS_Kfree(void *obj)
+{
+ if (obj) {
+ kfree(obj);
+ }
+}
+
+
+/**
+ * @brief Yields the current cpu to other runnable tasks.
+ */
+
+static inline void
+CommOS_Yield(void)
+{
+ cond_resched();
+}
+
+
+/**
+ * @brief Gets the current time in milliseconds.
+ * @return Current time in milliseconds, with precision of at most one tick.
+ */
+
+static inline unsigned long long
+CommOS_GetCurrentMillis(void)
+{
+ return (unsigned long long)jiffies_to_msecs(jiffies);
+}
+
+
+/**
+ * @brief Initializes given list.
+ * @param list list to initialize.
+ */
+
+static inline void
+CommOS_ListInit(CommOSList *list)
+{
+ INIT_LIST_HEAD(list);
+}
+
+
+/**
+ * @brief Tests if list is empty.
+ * @param list list to test.
+ * @return non-zero if empty, zero otherwise.
+ */
+
+#define CommOS_ListEmpty(list) list_empty((list))
+
+
+/**
+ * @brief Adds given element to beginning of list.
+ * @param list list to add to.
+ * @param elem element to add.
+ */
+
+#define CommOS_ListAdd(list, elem) list_add((elem), (list))
+
+
+/**
+ * @brief Adds given element to end of list.
+ * @param list list to add to.
+ * @param elem element to add.
+ */
+
+#define CommOS_ListAddTail(list, elem) list_add_tail((elem), (list))
+
+
+/**
+ * @brief Deletes given element from its list.
+ * @param elem element to delete.
+ */
+
+#define CommOS_ListDel(elem) \
+ do { \
+ list_del((elem)); \
+ INIT_LIST_HEAD((elem)); \
+ } while (0)
+
+
+/**
+ * @brief Iterates over a list.
+ * @param list list to iterate over.
+ * @param[out] item stores next element.
+ * @param itemListFieldName name in the item structure storing the list head.
+ */
+
+#define CommOS_ListForEach(list, item, itemListFieldName) \
+ list_for_each_entry((item), (list), itemListFieldName)
+
+
+/**
+ * @brief Iterates safely over a list.
+ * @param list list to iterate over.
+ * @param[out] item stores next element. May be deleted in the loop.
+ * @param[out] tmpItem saves iteration element.
+ * @param itemListFieldName name in the item structure storing the list head.
+ */
+
+#define CommOS_ListForEachSafe(list, item, tmpItem, itemListFieldName) \
+ list_for_each_entry_safe((item), (tmpItem), (list), itemListFieldName)
+
+
+/**
+ * @brief Combines two lists, adds second list to beginning of first one.
+ * @param list list to add to.
+ * @param list2 list to add.
+ */
+
+#define CommOS_ListSplice(list, list2) list_splice((list2), (list))
+
+
+/**
+ * @brief Combines two lists, adds second list to end of first one.
+ * @param list list to add to.
+ * @param list2 list to add.
+ */
+
+#define CommOS_ListSpliceTail(list, list2) list_splice_tail((list2), (list))
+
+
+/**
+ * @brief Gets current module handle.
+ * @return module handle.
+ */
+
+static inline CommOSModule
+CommOS_ModuleSelf(void)
+{
+ return THIS_MODULE;
+}
+
+
+/**
+ * @brief Retains module.
+ * @param[in,out] module to retain.
+ * @return zero if successful, non-zero otherwise.
+ */
+
+static inline int
+CommOS_ModuleGet(CommOSModule module)
+{
+ int rc = 0;
+
+ if (!module) {
+ goto out;
+ }
+ if (!try_module_get(module)) {
+ rc = -1;
+ }
+
+out:
+ return rc;
+}
+
+
+/**
+ * @brief Releases module.
+ * @param[in,out] module to release.
+ */
+
+static inline void
+CommOS_ModulePut(CommOSModule module)
+{
+ if (module) {
+ module_put(module);
+ }
+}
+
+
+/**
+ * @brief Inserts r/w memory barrier.
+ */
+
+#define CommOS_MemBarrier smp_mb
+
+#endif /* _COMM_OS_LINUX_H_ */
diff --git a/arch/arm/mvp/commkm/comm_os_mod_linux.c b/arch/arm/mvp/commkm/comm_os_mod_linux.c
new file mode 100644
index 0000000..8470de6
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_os_mod_linux.c
@@ -0,0 +1,105 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Linux-specific module loading, unloading functions.
+ */
+
+#include "comm_os.h"
+#include "comm_os_mod_ver.h"
+
+#include <linux/moduleparam.h>
+
+
+/* Module parameters -- passed as one 'name=value'-list string. */
+
+static char modParams[256];
+module_param_string(COMM_OS_MOD_SHORT_NAME, modParams, sizeof modParams, 0644);
+
+
+/**
+ * @brief Module initialization entry point. Calls the commOSModInit
+ * function pointer to perform upper layer initialization.
+ * @return zero if successful, non-zero otherwise.
+ */
+
+static int __init
+ModInit(void)
+{
+ int rc;
+
+ if (!commOSModInit) {
+ CommOS_Log(("%s: Can't find \'init\' function for module \'" \
+ COMM_OS_MOD_SHORT_NAME_STRING "\'.\n", __FUNCTION__));
+ return -1;
+ }
+
+ CommOS_Debug(("%s: Module parameters: [%s].\n", __FUNCTION__, modParams));
+
+ rc = (*commOSModInit)(modParams);
+ if (rc == 0) {
+ CommOS_Log(("%s: Module \'" COMM_OS_MOD_SHORT_NAME_STRING \
+ "\' has been successfully initialized.\n", __FUNCTION__));
+ } else {
+ CommOS_Log(("%s: Module \'" COMM_OS_MOD_SHORT_NAME_STRING \
+ "\' could not be initialized [%d].\n", __FUNCTION__, rc));
+ }
+
+ return rc > 0 ? -rc : rc;
+}
+
+
+/**
+ * @brief Module exit function. Calls the commOSModExit function pointer
+ * to perform upper layer cleanup.
+ */
+
+static void __exit
+ModExit(void)
+{
+ if (!commOSModExit) {
+ CommOS_Log(("%s: Can't find \'fini\' function for module \'" \
+ COMM_OS_MOD_SHORT_NAME_STRING "\'.\n", __FUNCTION__));
+ return;
+ }
+
+ (*commOSModExit)();
+ CommOS_Log(("%s: Module \'" COMM_OS_MOD_SHORT_NAME_STRING \
+ "\' has been stopped.\n", __FUNCTION__));
+}
+
+
+module_init(ModInit);
+module_exit(ModExit);
+
+/* Module information. */
+MODULE_AUTHOR("VMware, Inc.");
+MODULE_DESCRIPTION(COMM_OS_MOD_NAME_STRING);
+MODULE_VERSION(COMM_OS_MOD_VERSION_STRING);
+MODULE_LICENSE("GPL v2");
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
diff --git a/arch/arm/mvp/commkm/comm_os_mod_ver.h b/arch/arm/mvp/commkm/comm_os_mod_ver.h
new file mode 100644
index 0000000..059854c
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_os_mod_ver.h
@@ -0,0 +1,38 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Version definitions for the Comm module.
+ */
+
+#ifndef _COMM_OS_MOD_VER_H_
+#define _COMM_OS_MOD_VER_H_
+
+#define COMM_OS_MOD_NAME_STRING "VMware communication module"
+#define COMM_OS_MOD_SHORT_NAME comm
+#define COMM_OS_MOD_SHORT_NAME_STRING "comm"
+
+#define COMM_OS_MOD_VERSION 1.0.0.0
+#define COMM_OS_MOD_VERSION_COMMAS 1,0,0,0
+#define COMM_OS_MOD_VERSION_STRING "1.0.0.0"
+
+#endif /* _COM_OS_MOD_VER_H_ */
diff --git a/arch/arm/mvp/commkm/comm_svc.c b/arch/arm/mvp/commkm/comm_svc.c
new file mode 100644
index 0000000..18f62bd
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_svc.c
@@ -0,0 +1,421 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Communication functions based on transport functionality.
+ */
+
+#include "comm_os.h"
+#include "comm_os_mod_ver.h"
+#include "comm_svc.h"
+
+
+/*
+ * Initialization of module entry and exit callbacks expected by module
+ * loading/unloading functions in comm_os.
+ */
+
+static int Init(void *args);
+static void Exit(void);
+
+COMM_OS_MOD_INIT(Init, Exit);
+
+static volatile int running; // Initialized and running.
+
+
+/**
+ * @brief Allocates and initializes comm global state.
+ * Starts input dispatch and aio threads.
+ * @param argsIn arguments
+ * @return zero if successful, non-zero otherwise.
+ */
+
+static int
+Init(void *argsIn)
+{
+ int rc = -1;
+ unsigned int maxChannels = 8;
+ /*
+ * Infinite timeout, 1 polling cycle
+ * see kernel/time.c: msecs_to_jiffies()
+ */
+ unsigned int pollingMillis = (unsigned int)-1;
+ unsigned int pollingCycles = 1;
+ const char *args = argsIn;
+
+ if (args && *args) {
+ /* coverity[secure_coding] */
+ sscanf(args,
+ "max_channels:%u,poll_millis:%u,poll_cycles:%u",
+ &maxChannels, &pollingMillis, &pollingCycles);
+ CommOS_Debug(("%s: arguments [%s].\n", __FUNCTION__, args));
+ }
+
+ rc = Comm_Init(maxChannels);
+ if (rc) {
+ goto out;
+ }
+
+ rc = CommOS_StartIO(COMM_OS_MOD_SHORT_NAME_STRING "-disp",
+ Comm_DispatchAll, pollingMillis, pollingCycles,
+ COMM_OS_MOD_SHORT_NAME_STRING "-aio");
+ if (rc) {
+ unsigned long long timeout = 0;
+
+ Comm_Finish(&timeout); /* Nothing started, guaranteed to succeed. */
+ goto out;
+ }
+ running = 1;
+ rc = 0;
+
+out:
+ return rc;
+}
+
+
+/**
+ * @brief Attempts to close all channels.
+ * @return zero if successful, non-zero otherwise.
+ */
+
+static int
+Halt(void)
+{
+ unsigned int maxTries = 10;
+ int rc = -1;
+
+ if (!running) {
+ rc = 0;
+ goto out;
+ }
+
+ for ( ; maxTries; maxTries--) {
+ unsigned long long timeout = 2000ULL;
+
+ CommOS_Debug(("%s: Attempting to halt...\n", __FUNCTION__));
+ if (!Comm_Finish(&timeout)) {
+ running = 0;
+ rc = 0;
+ break;
+ }
+ }
+
+out:
+ return rc;
+}
+
+
+/**
+ * @brief Stops the comm_rt module.
+ * If Halt() call successful, stops input dispatch and aio threads.
+ */
+
+static void
+Exit(void)
+{
+ if (!Halt()) {
+ CommOS_StopIO();
+ }
+}
+
+
+/**
+ * @brief Registers an implementation block used when attaching to channels
+ * in response to transport attach events.
+ * @param impl implementation block.
+ * @return 0 if successful, non-zero otherwise.
+ */
+
+int
+CommSvc_RegisterImpl(const CommImpl *impl)
+{
+ return Comm_RegisterImpl(impl);
+}
+
+
+/**
+ * @brief Unregisters an implementation block used when attaching to channels
+ * in response to transport attach events.
+ * @param impl implementation block.
+ */
+
+void
+CommSvc_UnregisterImpl(const CommImpl *impl)
+{
+ Comm_UnregisterImpl(impl);
+}
+
+
+/**
+ * @brief Finds a free entry and initializes it with the information provided.
+ * May be called from BH. It doesn't call potentially blocking functions.
+ * @param transpArgs transport initialization arguments.
+ * @param impl implementation block.
+ * @param inBH non-zero if called in bottom half.
+ * @param[out] newChannel newly allocated channel.
+ * @return zero if successful, non-zero otherwise.
+ * @sideeffects Initializes the communications channel with given parameters
+ */
+
+int
+CommSvc_Alloc(const CommTranspInitArgs *transpArgs,
+ const CommImpl *impl,
+ int inBH,
+ CommChannel *newChannel)
+{
+ return Comm_Alloc(transpArgs, impl, inBH, newChannel);
+}
+
+
+/**
+ * @brief Zombifies a channel. May fail if channel isn't active.
+ * @param channel channel to zombify.
+ * @param inBH non-zero if called in bottom half.
+ * @return zero if channel zombified, non-zero otherwise.
+ */
+
+int
+CommSvc_Zombify(CommChannel channel,
+ int inBH)
+{
+ return Comm_Zombify(channel, inBH);
+}
+
+
+/**
+ * @brief Reports whether a channel is active.
+ * @param channel channel to report on.
+ * @return non-zero if channel active, zero otherwise.
+ */
+
+int
+CommSvc_IsActive(CommChannel channel)
+{
+ return Comm_IsActive(channel);
+}
+
+
+/**
+ * @brief Retrieves a channel's transport initialization arguments.
+ * It doesn't lock, the caller must ensure the channel may be accessed.
+ * @param channel CommChannel structure to get initialization arguments from.
+ * @return initialization arguments used to allocate/attach to channel.
+ */
+
+CommTranspInitArgs
+CommSvc_GetTranspInitArgs(CommChannel channel)
+{
+ return Comm_GetTranspInitArgs(channel);
+}
+
+
+/**
+ * @brief Retrieves upper layer state (pointer). It doesn't lock, the caller
+ * must ensure the channel may be accessed.
+ * @param channel CommChannel structure to get state from.
+ * @return pointer to upper layer state.
+ */
+
+void *
+CommSvc_GetState(CommChannel channel)
+{
+ return Comm_GetState(channel);
+}
+
+
+/**
+ * @brief Writes a fully formatted packet (containing payload data, if
+ * applicable) to the specified channel.
+ *
+ * The operation may block until enough write space is available, but no
+ * more than the specified interval. The operation either writes the full
+ * amount of bytes, or it fails. Warning: callers must _not_ use the
+ * _Lock/_Unlock functions to bracket calls to this function.
+ * @param[in,out] channel channel to write to.
+ * @param packet packet to write.
+ * @param[in,out] timeoutMillis interval in milliseconds to wait.
+ * @return number of bytes written, 0 if it times out, -1 error.
+ * @sideeffects Data may be written to the channel.
+ */
+
+int
+CommSvc_Write(CommChannel channel,
+ const CommPacket *packet,
+ unsigned long long *timeoutMillis)
+{
+ return Comm_Write(channel, packet, timeoutMillis);
+}
+
+
+/**
+ * @brief Writes a packet and associated payload data to the specified channel.
+ *
+ * The operation may block until enough write space is available, but not
+ * more than the specified interval. The operation either writes the full
+ * amount of bytes, or it fails. Users may call this function successively
+ * to write several packets from large {io|k}vecs. If that's the case, the
+ * packet header needs to be updated in between calls, for the different
+ * (total) lengths. Warning: callers must _not_ use the _Lock/_Unlock
+ * functions to bracket calls to this function.
+ * @param[in,out] channel the specified channel
+ * @param packet packet to write
+ * @param[in,out] vec kvec to write from
+ * @param[in,out] vecLen length of kvec
+ * @param[in,out] timeoutMillis interval in milliseconds to wait
+ * @param[in,out] iovOffset must be set to 0 before first call (internal cookie)
+ * @return number of bytes written, 0 if it timed out, -1 error
+ * @sideeffects data may be written to the channel
+ */
+
+int
+CommSvc_WriteVec(CommChannel channel,
+ const CommPacket *packet,
+ struct kvec **vec,
+ unsigned int *vecLen,
+ unsigned long long *timeoutMillis,
+ unsigned int *iovOffset)
+{
+ return Comm_WriteVec(channel, packet, vec, vecLen, timeoutMillis, iovOffset);
+}
+
+
+/**
+ * @brief Releases channel ref count. This function is exported for the upper
+ * layer's 'activateNtf' callback which may be run asynchronously. The
+ * callback is protected from concurrent channel releases until it calls
+ * this function.
+ * @param[in,out] channel CommChannel structure to release.
+ */
+
+void
+CommSvc_Put(CommChannel channel)
+{
+ Comm_Put(channel);
+}
+
+
+/**
+ * @brief Uses the read lock. This function is exported for the upper layer
+ * such that it can order acquisition of a different lock (socket) with
+ * the release of the dispatch lock.
+ * @param[in,out] channel CommChannel structure to unlock.
+ */
+
+void
+CommSvc_DispatchUnlock(CommChannel channel)
+{
+ Comm_DispatchUnlock(channel);
+}
+
+
+/**
+ * @brief Lock the channel.
+ *
+ * Uses the writer lock. This function is exported for the upper layer
+ * to ensure that channel isn't closed while updating the layer state.
+ * It also guarantees that if the lock is taken, the entry is either ACTIVE
+ * or ZOMBIE. Operations using this function are expected to be short,
+ * since unlike the _Write functions, these callers cannot be signaled.
+ * @param[in,out] channel CommChannel structure to lock.
+ * @return zero if successful, -1 otherwise.
+ */
+
+int
+CommSvc_Lock(CommChannel channel)
+{
+ return Comm_Lock(channel);
+}
+
+
+/**
+ * @brief Unlock the channel.
+ *
+ * Uses the writer lock. This function is exported for the upper layer
+ * to ensure that channel isn't closed while updating the layer state.
+ * See Comm_WriteLock for details).
+ * @param[in,out] channel CommChannel structure to unlock.
+ */
+
+void
+CommSvc_Unlock(CommChannel channel)
+{
+ Comm_Unlock(channel);
+}
+
+
+/**
+ * @brief Schedules a work item on the AIO thread(s).
+ * @param[in,out] work work item to be scheduled.
+ * @return zero if successful, -1 otherwise.
+ */
+
+int
+CommSvc_ScheduleAIOWork(CommOSWork *work)
+{
+ return CommOS_ScheduleAIOWork(work);
+}
+
+
+/**
+ * @brief Requests events be posted in-line after the function completes.
+ * @param channel channel object.
+ * @return current number of requests for inline event posting, or -1 on error.
+ */
+
+unsigned int
+CommSvc_RequestInlineEvents(CommChannel channel)
+{
+ return Comm_RequestInlineEvents(channel);
+}
+
+
+/**
+ * @brief Requests events be posted out-of-band after the function completes.
+ * @param channel channel object.
+ * @return current number of requests for inline event posting, or -1 on error.
+ */
+
+unsigned int
+CommSvc_ReleaseInlineEvents(CommChannel channel)
+{
+ return Comm_ReleaseInlineEvents(channel);
+}
+
+
+#if defined(__linux__)
+EXPORT_SYMBOL(CommSvc_RegisterImpl);
+EXPORT_SYMBOL(CommSvc_UnregisterImpl);
+EXPORT_SYMBOL(CommSvc_Alloc);
+EXPORT_SYMBOL(CommSvc_Zombify);
+EXPORT_SYMBOL(CommSvc_IsActive);
+EXPORT_SYMBOL(CommSvc_GetTranspInitArgs);
+EXPORT_SYMBOL(CommSvc_GetState);
+EXPORT_SYMBOL(CommSvc_Write);
+EXPORT_SYMBOL(CommSvc_WriteVec);
+EXPORT_SYMBOL(CommSvc_Put);
+EXPORT_SYMBOL(CommSvc_DispatchUnlock);
+EXPORT_SYMBOL(CommSvc_Lock);
+EXPORT_SYMBOL(CommSvc_Unlock);
+EXPORT_SYMBOL(CommSvc_ScheduleAIOWork);
+EXPORT_SYMBOL(CommSvc_RequestInlineEvents);
+EXPORT_SYMBOL(CommSvc_ReleaseInlineEvents);
+#endif // defined(__linux__)
diff --git a/arch/arm/mvp/commkm/comm_svc.h b/arch/arm/mvp/commkm/comm_svc.h
new file mode 100644
index 0000000..c4f3292
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_svc.h
@@ -0,0 +1,71 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Communication functions exported by the comm_rt module.
+ */
+
+#ifndef _COMM_SVC_H_
+#define _COMM_SVC_H_
+
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#include "comm.h"
+
+int CommSvc_RegisterImpl(const CommImpl *impl);
+void CommSvc_UnregisterImpl(const CommImpl *impl);
+int CommSvc_Zombify(CommChannel channel, int inBH);
+int CommSvc_IsActive(CommChannel channel);
+CommTranspInitArgs CommSvc_GetTranspInitArgs(CommChannel channel);
+void *CommSvc_GetState(CommChannel channel);
+void CommSvc_Put(CommChannel channel);
+void CommSvc_DispatchUnlock(CommChannel channel);
+int CommSvc_Lock(CommChannel channel);
+void CommSvc_Unlock(CommChannel channel);
+int CommSvc_ScheduleAIOWork(CommOSWork *work);
+
+int
+CommSvc_Alloc(const CommTranspInitArgs *transpArgs,
+ const CommImpl *impl,
+ int inBH,
+ CommChannel *newChannel);
+
+int
+CommSvc_Write(CommChannel channel,
+ const CommPacket *packet,
+ unsigned long long *timeoutMillis);
+
+int
+CommSvc_WriteVec(CommChannel channel,
+ const CommPacket *packet,
+ struct kvec **vec,
+ unsigned int *vecLen,
+ unsigned long long *timeoutMillis,
+ unsigned int *iovOffset);
+
+unsigned int CommSvc_RequestInlineEvents(CommChannel channel);
+unsigned int CommSvc_ReleaseInlineEvents(CommChannel channel);
+
+#endif // _COMM_SVC_H_
diff --git a/arch/arm/mvp/commkm/comm_transp.h b/arch/arm/mvp/commkm/comm_transp.h
new file mode 100644
index 0000000..6cc58ae
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_transp.h
@@ -0,0 +1,90 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Generic shared memory transport API.
+ */
+
+#ifndef _COMM_TRANSP_H_
+#define _COMM_TRANSP_H_
+
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+/*
+ * Common shared memory identifier.
+ * External handle that makes sense to both hypervisor and guest.
+ */
+
+#define COMM_TRANSP_ID_8_ANY ((unsigned char)-1)
+#define COMM_TRANSP_ID_32_ANY ((unsigned int)-1)
+#define COMM_TRANSP_ID_64_ANY ((unsigned long long)-1)
+
+
+typedef struct CommTranspID {
+ union {
+ unsigned char d8[8];
+ unsigned int d32[2];
+ unsigned long long d64;
+ };
+} CommTranspID;
+
+
+/* Basic initialization arguments. */
+
+typedef enum CommTranspInitMode {
+ COMM_TRANSP_INIT_CREATE = 0x0,
+ COMM_TRANSP_INIT_ATTACH = 0x1
+} CommTranspInitMode;
+
+typedef struct CommTranspInitArgs {
+ unsigned int capacity; // Shared memory capacity.
+ unsigned int type; // Type / implementation using this area.
+ CommTranspID id; // ID (name) of shared memory area.
+ CommTranspInitMode mode; // Init mode (above).
+} CommTranspInitArgs;
+
+
+/**
+ * @brief Generate a type id from description (protocol) string. This function
+ * uses djb2, a string hashing algorithm by Dan Bernstein.
+ * (see http://www.cse.yorku.ca/~oz/hash.html)
+ * @param str string to hash
+ * @return 32-bit hash value
+ */
+
+static inline unsigned int
+CommTransp_GetType(const char *str)
+{
+ unsigned int hash = 5381;
+ int c;
+
+ while ((c = *str++)) {
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+ }
+ return hash;
+}
+
+#endif // _COMM_TRANSP_H_
diff --git a/arch/arm/mvp/commkm/comm_transp_impl.h b/arch/arm/mvp/commkm/comm_transp_impl.h
new file mode 100644
index 0000000..113cd21
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_transp_impl.h
@@ -0,0 +1,165 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Generic shared memory transport private API.
+ */
+
+#ifndef _COMM_TRANSP_IMPL_H_
+#define _COMM_TRANSP_IMPL_H_
+
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#include "comm_transp.h"
+
+
+/* Shared memory opaque descriptor/handle. Only meaningful locally. */
+
+typedef struct CommTranspPriv *CommTransp;
+
+
+/* Asynchronous signaling initialization arguments. */
+
+typedef enum CommTranspIOEvent {
+ COMM_TRANSP_IO_DETACH = 0x0,
+ COMM_TRANSP_IO_IN = 0x1,
+ COMM_TRANSP_IO_OUT = 0x2,
+ COMM_TRANSP_IO_INOUT = 0x3
+} CommTranspIOEvent;
+
+typedef struct CommTranspEvent {
+ void (*ioEvent)(CommTransp transp, CommTranspIOEvent event, void *data);
+ void *ioEventData;
+} CommTranspEvent;
+
+
+/*
+ * Mechanism to detect and optionally attach to, created shared memory regions.
+ */
+
+typedef struct CommTranspListener {
+ int (*probe)(CommTranspInitArgs *transpArgs, void *probeData);
+ void *probeData;
+} CommTranspListener;
+
+
+
+/*
+ * Function prototypes.
+ */
+
+int CommTranspEvent_Init(void);
+void CommTranspEvent_Exit(void);
+int CommTranspEvent_Process(CommTranspID *transpID, CommTranspIOEvent event);
+int
+CommTranspEvent_Raise(unsigned int peerEvID,
+ CommTranspID *transpID,
+ CommTranspIOEvent event);
+
+int CommTransp_Init(void);
+void CommTransp_Exit(void);
+
+int CommTransp_Register(const CommTranspListener *listener);
+void CommTransp_Unregister(const CommTranspListener *listener);
+int
+CommTransp_Notify(const CommTranspID *notificationCenterID,
+ CommTranspInitArgs *transpArgs);
+
+int
+CommTransp_Open(CommTransp *transp,
+ CommTranspInitArgs *transpArgs,
+ CommTranspEvent *transpEvent);
+void CommTransp_Close(CommTransp transp);
+
+int CommTransp_EnqueueSpace(CommTransp transp);
+int CommTransp_EnqueueReset(CommTransp transp);
+int CommTransp_EnqueueCommit(CommTransp transp);
+int
+CommTransp_EnqueueSegment(CommTransp transp,
+ const void *buf,
+ unsigned int bufLen);
+
+int CommTransp_DequeueSpace(CommTransp transp);
+int CommTransp_DequeueReset(CommTransp transp);
+int CommTransp_DequeueCommit(CommTransp transp);
+int
+CommTransp_DequeueSegment(CommTransp transp,
+ void *buf,
+ unsigned int bufLen);
+
+unsigned int CommTransp_RequestInlineEvents(CommTransp transp);
+unsigned int CommTransp_ReleaseInlineEvents(CommTransp transp);
+
+
+/**
+ * @brief Enqueues data into the transport object, data is available for
+ * reading immediately.
+ * @param transp handle to the transport object.
+ * @param buf bytes to enqueue.
+ * @param bufLen number of bytes to enqueue.
+ * @return number of bytes enqueued on success, < 0 otherwise.
+ */
+
+static inline int
+CommTransp_EnqueueAtomic(CommTransp transp,
+ const void *buf,
+ unsigned int bufLen)
+{
+ int rc;
+
+ CommTransp_EnqueueReset(transp);
+ rc = CommTransp_EnqueueSegment(transp, buf, bufLen);
+ if (CommTransp_EnqueueCommit(transp)) {
+ rc = -1;
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Dequeues data from the transport object into a buffer.
+ * @param transp handle to the transport object.
+ * @param[out] buf buffer to copy to.
+ * @param bufLen number of bytes to dequeue.
+ * @return number of bytes dequeued on success, < 0 otherwise,
+ */
+
+static inline int
+CommTransp_DequeueAtomic(CommTransp transp,
+ void *buf,
+ unsigned int bufLen)
+{
+ int rc;
+
+ CommTransp_DequeueReset(transp);
+ rc = CommTransp_DequeueSegment(transp, buf, bufLen);
+ if (CommTransp_DequeueCommit(transp)) {
+ rc = -1;
+ }
+ return rc;
+}
+
+#endif // _COMM_TRANSP_IMPL_H_
diff --git a/arch/arm/mvp/commkm/comm_transp_mvp.c b/arch/arm/mvp/commkm/comm_transp_mvp.c
new file mode 100644
index 0000000..f755de9
--- /dev/null
+++ b/arch/arm/mvp/commkm/comm_transp_mvp.c
@@ -0,0 +1,944 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Generic shared memory transport API.
+ */
+#include <linux/wait.h>
+
+#include "comm_os.h"
+#include "comm_transp_impl.h"
+
+#include "mvp_types.h"
+#include "qp.h"
+
+
+/*
+ * Opaque CommTransp structure. See comm_transp.h
+ */
+
+struct CommTranspPriv {
+ QPHandle *qp;
+ CommTranspEvent event;
+ unsigned int peerEvID;
+ unsigned int writeSize;
+ unsigned int readSize;
+ uint32 backRef;
+ CommOSWork work;
+ CommOSAtomic raiseInline;
+};
+
+/*
+ * Transport table object accounting
+ */
+
+typedef struct TranspTableEntry {
+ CommOSAtomic holds;
+ CommTransp transp;
+ CommOSWaitQueue wq;
+} TranspTableEntry;
+
+TranspTableEntry transpTable[QP_MAX_QUEUE_PAIRS];
+static CommOSSpinlock_Define(transpTableLock);
+
+/**
+ * @brief Destroy the transport object
+ * @param transp transport object to destroy
+ * @sideeffects detaches from queue pair
+ */
+
+static void
+DestroyTransp(CommTransp transp)
+{
+ CommTranspID transpID;
+ int32 rc;
+
+ if (!transp) {
+ CommOS_Debug(("Failed to close channel: Bad handle\n"));
+ return;
+ }
+
+ CommOS_Log(("%s: Detaching channel [%u:%u]\n",
+ __FUNCTION__,
+ transp->qp->id.context,
+ transp->qp->id.resource));
+
+ transpID.d32[0] = transp->qp->id.context;
+ transpID.d32[1] = transp->qp->id.resource;
+
+#if !defined(COMM_BUILDING_SERVER)
+ /*
+ * Tell the host to detach, will block in the host
+ * until the host has unmapped memory. Once the
+ * host has unmapped, it is safe to free.
+ */
+ CommTranspEvent_Raise(transp->peerEvID,
+ &transpID,
+ COMM_TRANSP_IO_DETACH);
+#endif
+
+ rc = QP_Detach(transp->qp);
+
+#if defined(COMM_BUILDING_SERVER)
+ /*
+ * Wake up waiters now that unmapping is complete
+ */
+ CommOS_WakeUp(&transpTable[transp->backRef].wq);
+#endif
+
+ CommOS_Kfree(transp);
+ if (rc != QP_SUCCESS) {
+ CommOS_Log(("%s: Failed to detach. rc: %d\n", __FUNCTION__, rc));
+ } else {
+ CommOS_Log(("%s: Channel detached.\n", __FUNCTION__));
+ }
+}
+
+
+/**
+ * @brief Initialize the transport object table
+ */
+
+static void
+TranspTableInit(void)
+{
+ uint32 i;
+ CommOS_SpinLock(&transpTableLock);
+ for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) {
+ CommOS_WriteAtomic(&transpTable[i].holds, -1);
+ transpTable[i].transp = NULL;
+ }
+ CommOS_SpinUnlock(&transpTableLock);
+}
+
+
+/**
+ * @brief Add a transport object into the table
+ * @param transp handle to the transport object
+ * @return 0 on success, -1 otherwise
+ * @sideeffects increments entry refcount
+ */
+
+static inline int32
+TranspTableAdd(CommTransp transp)
+{
+ uint32 i;
+
+ if (!transp) {
+ return -1;
+ }
+
+ CommOS_SpinLock(&transpTableLock);
+ for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) {
+ if ((transpTable[i].transp) == NULL) {
+ transpTable[i].transp = transp;
+ CommOS_WriteAtomic(&transpTable[i].holds, 1);
+ CommOS_WaitQueueInit(&transpTable[i].wq);
+ transp->backRef = i;
+ break;
+ }
+ }
+ CommOS_SpinUnlock(&transpTableLock);
+
+ return 0;
+}
+
+/**
+ * @brief retrieve a transport object and increment its ref count
+ * @param id transport id to retrieve
+ * @return transport object, or NULL if not found
+ * @sideeffects increments entry ref count
+ */
+
+static inline CommTransp
+TranspTableGet(CommTranspID *id)
+{
+ CommTransp transp;
+ uint32 i;
+
+ if (!id) {
+ return NULL;
+ }
+
+ for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) {
+ transp = transpTable[i].transp;
+ if (transp &&
+ (transp->qp->id.context == id->d32[0]) &&
+ (transp->qp->id.resource == id->d32[1])) {
+ CommOS_AddReturnAtomic(&transpTable[i].holds, 1);
+ return transp;
+ }
+ }
+ CommOS_Debug(("%s: couldn't find transport object\n", __FUNCTION__));
+
+ return NULL;
+}
+
+/**
+ * @brief Puts back a previously TranspGet-ed transport object.
+ * @param transp the transport object.
+ * @sideeffects decrements the transport reference count.
+ * frees object if refcount now zero
+ */
+
+static inline void
+TranspTablePut(CommTransp transp)
+{
+ int32 holds;
+ int32 backRef;
+ if (!transp) {
+ return;
+ }
+
+ backRef = transp->backRef;
+ BUG_ON(backRef >= QP_MAX_QUEUE_PAIRS);
+
+ holds = CommOS_SubReturnAtomic(&transpTable[backRef].holds, 1);
+ if (holds > 0) {
+ return;
+ }
+ BUG_ON(holds < 0);
+
+ CommOS_SpinLock(&transpTableLock);
+ CommOS_WriteAtomic(&transpTable[backRef].holds, -1);
+ transpTable[backRef].transp = NULL;
+ CommOS_SpinUnlock(&transpTableLock);
+ DestroyTransp(transp);
+}
+
+
+/**
+ * @brief Puts back a previously TranspGet-ed transport object.
+ * @param transp the transport object.
+ * @sideeffects decrements the transport reference count.
+ * asserts that remaining count > 0
+ */
+
+static inline void
+TranspTablePutNF(CommTransp transp)
+{
+ int32 holds;
+ int32 backRef;
+ if (!transp) {
+ return;
+ }
+
+ backRef = transp->backRef;
+ BUG_ON(backRef >= QP_MAX_QUEUE_PAIRS);
+
+ holds = CommOS_SubReturnAtomic(&transpTable[backRef].holds, 1);
+ BUG_ON(holds <= 0);
+}
+
+
+/**
+ * @brief Raises INOUT event in-line or out-of-band. Note that this function
+ * expects the transport object to be held prior to being called.
+ * @param arg work item of transport object.
+ */
+
+static void
+RaiseEvent(CommOSWork *arg)
+{
+#if !defined(__linux__)
+#error "RaiseEvent() is only supported on linux. Port 'container_of'!"
+#endif
+ CommTransp transp = container_of(arg, struct CommTranspPriv, work);
+ CommTranspID transpID = {{
+ .d32 = {
+ [0] = transp->qp->id.context,
+ [1] = transp->qp->id.resource
+ }
+ }};
+
+ CommTranspEvent_Raise(transp->peerEvID,
+ &transpID,
+ COMM_TRANSP_IO_INOUT);
+ TranspTablePut(transp);
+}
+
+
+/**
+ * @brief Requests events be posted in-line after the function completes.
+ * @param transp transport object.
+ * @return current number of requests for inline event posting.
+ * @sideeffects posts an event on the first transition to in-line processing.
+ */
+
+unsigned int
+CommTransp_RequestInlineEvents(CommTransp transp)
+{
+ unsigned int res = CommOS_AddReturnAtomic(&transp->raiseInline, 1);
+ if (res == 1) {
+ /* On the first (effective) transition, make sure an event is raised. */
+
+ CommOS_AddReturnAtomic(&transpTable[transp->backRef].holds, 1);
+ RaiseEvent(&transp->work);
+ }
+ return res;
+}
+
+
+/**
+ * @brief Requests events be posted out-of-band after the function completes.
+ * @param transp transport object.
+ * @return current number of requests for inline event posting.
+ */
+
+unsigned int
+CommTransp_ReleaseInlineEvents(CommTransp transp)
+{
+ return CommOS_SubReturnAtomic(&transp->raiseInline, 1);
+}
+
+
+/*
+ * Comm Offload server callbacks.
+ */
+
+#if defined(COMM_BUILDING_SERVER)
+
+#define COMM_MAX_LISTENERS QP_MAX_LISTENERS
+
+static int32 NotifyCB(const QPInitArgs *args);
+static void DetachCB(void *data);
+
+static CommOSSpinlock_Define(listenersLock);
+static CommTranspListener listeners[COMM_MAX_LISTENERS];
+static uint32 numListeners = 0;
+
+
+/**
+ * @brief Notify callback when guests attach to queue pairs. Notifies any
+ * registered listeners (e.g. Comm layer).
+ * @param args Initialization arguments used by the guest to initialize
+ * its queue pair
+ * @return 0 on success, <0 otherwise. see qp.h for error codes.
+ */
+
+static int32
+NotifyCB(const QPInitArgs* args)
+{
+ CommTranspInitArgs transpArgs;
+ uint32 i;
+ int32 rc = -1;
+
+ if (!args) {
+ return QP_ERROR_INVALID_ARGS;
+ }
+
+ transpArgs.id.d32[0] = args->id.context;
+ transpArgs.id.d32[1] = args->id.resource;
+ transpArgs.capacity = args->capacity;
+ transpArgs.type = args->type;
+
+ CommOS_SpinLock(&listenersLock);
+ for (i = 0; i < COMM_MAX_LISTENERS; i++) {
+ if (listeners[i].probe &&
+ (listeners[i].probe(&transpArgs, listeners[i].probeData) == 0)) {
+ CommOS_Debug(("%s: Delivered notify event to listener %u\n",
+ __FUNCTION__,
+ i));
+ rc = 0;
+ break;
+ }
+ }
+ CommOS_SpinUnlock(&listenersLock);
+ return rc;
+}
+
+
+/**
+ * @brief Detach callback when guests detach from queue pairs. Notifies
+ * any registered listeners (e.g. CommComm layer).
+ * @param data Transport object passed when the callback was registered
+ */
+
+static void
+DetachCB(void *data)
+{
+ CommTransp transp = data;
+ if (!transp || !(transp->event.ioEvent)) {
+ return;
+ }
+ CommOS_Debug(("%s: Guest detached from [%u:%u]\n",
+ __FUNCTION__,
+ transp->qp->id.context,
+ transp->qp->id.resource));
+ transp->event.ioEvent(transp, COMM_TRANSP_IO_DETACH, transp->event.ioEventData);
+}
+#endif
+
+
+/**
+ * @brief Performs one-time initialization of mvp transport provider.
+ * @return 0 on success, < 0 otherwise.
+ */
+
+int
+CommTransp_Init(void)
+{
+ int32 rc;
+ TranspTableInit();
+
+ rc = CommTranspEvent_Init();
+
+#if defined(COMM_BUILDING_SERVER)
+ if (!rc) {
+ QP_RegisterListener(NotifyCB);
+ }
+#endif
+ return rc;
+}
+
+
+/**
+ * @brief Performs clean-up of mvp transport provider.
+ */
+
+void
+CommTransp_Exit(void)
+{
+ CommTranspEvent_Exit();
+#if defined(COMM_BUILDING_SERVER)
+ QP_UnregisterListener(NotifyCB);
+#endif
+}
+
+#if defined(COMM_BUILDING_SERVER)
+
+/**
+ * @brief Checks for a successful detach from Comm
+ * @param arg1 back reference index for channel in transport table
+ * @param arg2 ignored
+ * @return 1 if detach completed, 0 otherwise
+ */
+
+static int
+DetachCondition(void *arg1, void *arg2)
+{
+ uint32 backRef = (uint32)arg1;
+
+ return (CommOS_ReadAtomic(&transpTable[backRef].holds) == -1);
+}
+#endif
+
+
+/**
+ * @brief Processes a raised signal event. This is a callback function called
+ * from a comm_transp_ev plugin when a signal is received. Delivers an event
+ * to one or more channels. If id->d32[1] == COMM_TRANSP_ID_32_ANY, the event
+ * will be delivered to all registered channels associated with vmID
+ * id->d32[0].
+ * @param id identifies a transport object to signal.
+ * @param event type of event.
+ * @return 0 if delivered to at least one channel, -1 on failure.
+ */
+
+int
+CommTranspEvent_Process(CommTranspID *id,
+ CommTranspIOEvent event)
+{
+ int rc = 0;
+ unsigned int delivered = 0;
+ unsigned int backRef;
+ int i = 0;
+
+ CommTransp transp;
+ uint32 raiseOnAllChannels = (id->d32[1] == COMM_TRANSP_ID_32_ANY);
+ uint32 channels = raiseOnAllChannels ? QP_MAX_QUEUE_PAIRS : 1;
+
+ while (channels--) {
+ if (raiseOnAllChannels) {
+ id->d32[1] = i++;
+ }
+ transp = TranspTableGet(id);
+ if (transp) {
+ if (transp->event.ioEvent) {
+ transp->event.ioEvent(transp, event, transp->event.ioEventData);
+ }
+ backRef = transp->backRef;
+ TranspTablePut(transp);
+
+#if defined(COMM_BUILDING_SERVER)
+ /*
+ * Wait for unmap on IO_DETACH, return to monitor.
+ */
+ if (event == COMM_TRANSP_IO_DETACH) {
+ unsigned long long timeout = 30000;
+
+ rc = CommOS_Wait(&transpTable[backRef].wq,
+ DetachCondition,
+ (void*)backRef,
+ NULL,
+ &timeout);
+ switch (rc) {
+ case 1: // Memory successfully unmapped
+ rc = 0;
+ break;
+ default: // Timed out or other error.
+ return -1;
+ }
+ }
+#endif
+ delivered++;
+ }
+ }
+
+ rc = (delivered > 0) ? 0 : -1;
+ return rc;
+}
+
+
+/**
+ * @brief Register a listener to be notified when guests attach to the Comm
+ * offload server
+ * @param listener the listener to be notified
+ * @return 0 on success, -1 on failure
+ */
+
+int
+CommTransp_Register(const CommTranspListener *listener)
+{
+ int32 rc = -1;
+#if defined(COMM_BUILDING_SERVER)
+ uint32 i;
+
+ if (!listener) {
+ return -1;
+ }
+
+ CommOS_SpinLock(&listenersLock);
+ for (i = 0; i < COMM_MAX_LISTENERS; i++) {
+ if ((listeners[i].probe == NULL) &&
+ (listeners[i].probeData == NULL)) {
+ listeners[i] = *listener;
+ numListeners++;
+ rc = 0;
+ CommOS_Debug(("%s: Registered listener %u\n", __FUNCTION__, i));
+ break;
+ }
+ }
+ CommOS_SpinUnlock(&listenersLock);
+#endif
+ return rc;
+}
+
+
+/**
+ * @brief Unregisters a listener from the transport event notification system
+ * @param listener listener to unregister
+ * @return 0 on success
+ */
+
+void
+CommTransp_Unregister(const CommTranspListener *listener)
+{
+#if defined(COMM_BUILDING_SERVER)
+ uint32 i;
+
+ if (!listener || !listener->probe) {
+ return;
+ }
+
+
+ CommOS_SpinLock(&listenersLock);
+ for (i = 0; i < COMM_MAX_LISTENERS; i++) {
+ if ((listeners[i].probe == listener->probe) &&
+ (listeners[i].probeData == listener->probeData)) {
+ listeners[i].probe = NULL;
+ listeners[i].probeData = NULL;
+ numListeners--;
+ CommOS_Debug(("%s: Unregistered listener %u\n", __FUNCTION__, i));
+ }
+ }
+ CommOS_SpinUnlock(&listenersLock);
+#endif
+}
+
+
+/**
+ * @brief Allocates and initializes a transport object
+ * @param[in,out] transp handle to the transport to allocate and initialize
+ * @param transpArgs initialization arguments (see pvtcpTransp.h)
+ * @param transpEvent event callback to be delivered when events occur (e.g.
+ * detach events)
+ * @return 0 on success, <0 otherwise. See qp.h for error codes.
+ * @sideeffects Allocates memory
+ */
+
+int
+CommTransp_Open(CommTransp *transp,
+ CommTranspInitArgs *transpArgs,
+ CommTranspEvent *transpEvent)
+{
+ int32 rc = -1;
+ QPHandle *qp = NULL;
+ CommTransp transpOut = NULL;
+ QPInitArgs qpInitArgs;
+
+ if (!transp || !transpArgs) {
+ return -1;
+ }
+
+ CommOS_Log(("%s: Attaching to [%u:%u]. Capacity: %u\n",
+ __FUNCTION__,
+ transpArgs->id.d32[1],
+ transpArgs->id.d32[0],
+ transpArgs->capacity));
+
+ qpInitArgs.id.context = transpArgs->id.d32[0];
+ qpInitArgs.id.resource = transpArgs->id.d32[1];
+ qpInitArgs.capacity = transpArgs->capacity;
+ qpInitArgs.type = transpArgs->type;
+
+ if (!(transpOut = CommOS_Kmalloc(sizeof *transpOut))) {
+ rc = -1;
+ goto out;
+ }
+
+ /*
+ * Attach to the queue pair
+ */
+ rc = QP_Attach(&qpInitArgs, &qp);
+ if (rc < 0) {
+ rc = -1;
+ goto out;
+ }
+
+ transpOut->qp = qp;
+
+ /*
+ * Reassign ID so Comm knows what ID was actually given
+ */
+ transpArgs->id.d32[0] = qp->id.context;
+ transpArgs->id.d32[1] = qp->id.resource;
+
+ if (transpEvent) {
+ transpOut->event = *transpEvent;
+ } else {
+ transpOut->event.ioEvent = NULL;
+ transpOut->event.ioEventData = NULL;
+ }
+
+#if defined(COMM_BUILDING_SERVER)
+ CommOS_Debug(("%s: Registering detach CB on id %u...\n",
+ __FUNCTION__, transpArgs->id.d32[1]));
+ QP_RegisterDetachCB(transpOut->qp, DetachCB, transpOut);
+#endif
+
+ transpOut->peerEvID = COMM_TRANSP_ID_32_ANY;
+ transpOut->writeSize = 0;
+ transpOut->readSize = 0;
+ CommOS_InitWork(&transpOut->work, RaiseEvent);
+ CommOS_WriteAtomic(&transpOut->raiseInline, 0);
+
+ if (TranspTableAdd(transpOut)) {
+ CommOS_Log(("%s: Exceeded max limit of transport objects!\n",
+ __FUNCTION__));
+ DestroyTransp(transpOut);
+ rc = -1;
+ goto out;
+ }
+
+ *transp = transpOut;
+ rc = 0;
+
+ CommOS_Log(("%s: Channel attached.\n", __FUNCTION__));
+
+out:
+ if (rc && transpOut) {
+ CommOS_Log(("%s: Failed to attach: %d\n", __FUNCTION__, rc));
+ CommOS_Kfree(transpOut);
+ }
+
+ return rc;
+}
+
+
+/**
+ * @brief Tear down the transport channel, destroy the object if the refcount
+ * drops to zero
+ * @param transp handle to the transport channel
+ * @sideeffects decrements the entry's refcount
+ */
+
+void
+CommTransp_Close(CommTransp transp) {
+ if (!transp) {
+ return;
+ }
+ CommOS_FlushAIOWork(&transp->work);
+ TranspTablePut(transp);
+}
+
+
+/**
+ * @brief Returns available space for enqueue, in bytes
+ * @param transp handle to the transport object
+ * @return available space in the queue for enqueue operations, <0
+ * on error conditions. see qp.h for error codes.
+ */
+
+int
+CommTransp_EnqueueSpace(CommTransp transp)
+{
+ if (!transp) {
+ return -1;
+ }
+ return QP_EnqueueSpace(transp->qp);
+}
+
+
+/**
+ * @brief Discards any pending enqueues
+ * @param transp handle to the transport object
+ * @return 0 on success, <0 otherwise. see qp.h for error codes
+ */
+
+int
+CommTransp_EnqueueReset(CommTransp transp)
+{
+ if (!transp) {
+ return -1;
+ }
+ transp->writeSize = 0;
+ return QP_EnqueueReset(transp->qp);
+}
+
+
+/**
+ * @brief Enqueues a segment of data into the transport object
+ * @param transp handle to the transport object
+ * @param buf data to enqueue
+ * @param bufLen number of bytes to enqueue
+ * @return number of bytes enqueued on success, <0 otherwise. see qp.h
+ * for error codes
+ */
+
+int
+CommTransp_EnqueueSegment(CommTransp transp,
+ const void *buf,
+ unsigned int bufLen)
+{
+ int rc;
+
+ if (!transp) {
+ return -1;
+ }
+ rc = QP_EnqueueSegment(transp->qp, (void*)buf, bufLen);
+ if (rc >= 0) {
+ transp->writeSize += (unsigned int)rc;
+ } else {
+ transp->writeSize = 0;
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Commits any previous EnqueueSegment operations to the transport
+ * object.
+ * @param transp handle to the transport object.
+ * @return 0 on success, < 0 otherwise.
+ */
+
+int
+CommTransp_EnqueueCommit(CommTransp transp)
+{
+ int rc;
+
+ if (!transp) {
+ return -1;
+ }
+
+ rc = QP_EnqueueCommit(transp->qp);
+ if (rc >= 0) {
+ const unsigned int fudge = 4;
+ int writable = CommTransp_EnqueueSpace(transp);
+
+ if ((writable >= 0) &&
+ ((transp->writeSize + (unsigned int)writable + fudge) >=
+ transp->qp->queueSize)) {
+ /*
+ * If bytes written since last commit + writable space 'almost'
+ * equal write queue size, then signal. The 'almost' fudge factor
+ * accounts for a possibly inaccurate CommTransp_EnqueueSpace()
+ * return value. Most of the time, this is inconsequential. In
+ * rare, borderline occasions, it results in a few extra signals.
+ * The scheme essentially means this: if this is the first packet
+ * to be write-committed, we signal. Otherwise, the remote end is
+ * supposed to keep going for as long as it can read.
+ *
+ */
+
+ BUG_ON(transp->backRef >= QP_MAX_QUEUE_PAIRS);
+ CommOS_AddReturnAtomic(&transpTable[transp->backRef].holds, 1);
+ if (CommOS_ReadAtomic(&transp->raiseInline)) {
+ RaiseEvent(&transp->work);
+ } else if (CommOS_ScheduleAIOWork(&transp->work)) {
+ TranspTablePutNF(transp);
+ }
+ }
+ } else {
+ rc = -1;
+ }
+ transp->writeSize = 0;
+ return rc;
+}
+
+
+/**
+ * @brief Returns any available bytes for dequeue
+ * @param transp handle to the transport object
+ * @return available bytes for dequeue, <0 otherwise. see qp.h for error codes
+ */
+
+int
+CommTransp_DequeueSpace(CommTransp transp)
+{
+ if (!transp) {
+ return -1;
+ }
+ return QP_DequeueSpace(transp->qp);
+}
+
+
+/**
+ * @brief Discards any pending dequeues
+ * @param transp handle to the transport object
+ * @return 0 on success, <0 otherwise, see qp.h for error codes
+ */
+
+int
+CommTransp_DequeueReset(CommTransp transp)
+{
+ if (!transp) {
+ return -1;
+ }
+ transp->readSize = 0;
+ return QP_DequeueReset(transp->qp);
+}
+
+
+/**
+ * @brief Dequeues a segment of data from the consumer queue into
+ * a buffer
+ * @param transp handle to the transport object
+ * @param[out] buf buffer to copy to
+ * @param bufLen number of bytes to dequeue
+ * @return number of bytes dequeued on success, <0 otherwise,
+ * see qp.h for error codes
+ */
+
+int
+CommTransp_DequeueSegment(CommTransp transp,
+ void *buf,
+ unsigned bufLen)
+{
+ int rc;
+
+ if (!transp) {
+ return -1;
+ }
+ rc = QP_DequeueSegment(transp->qp, buf, bufLen);
+ if (rc >= 0) {
+ transp->readSize += (unsigned int)rc;
+ } else {
+ transp->readSize = 0;
+ }
+ return rc;
+}
+
+
+/**
+ * @brief Commits any previous DequeueSegment operations to the
+ * transport object.
+ * @param transp handle to the transport object.
+ * @return 0 on success, < 0 otherwise.
+ */
+
+int
+CommTransp_DequeueCommit(CommTransp transp)
+{
+ int rc;
+
+ if (!transp) {
+ return -1;
+ }
+ rc = QP_DequeueCommit(transp->qp);
+ if (rc >= 0) {
+ int readable = CommTransp_DequeueSpace(transp);
+ const unsigned int limit = transp->qp->queueSize / 2;
+
+ if ((readable >= 0) &&
+ (transp->readSize + (unsigned int)readable >= limit) &&
+ ((unsigned int)readable < limit)) {
+ /*
+ * Minimize the number of likely 'peer write OK' signalling:
+ * only do it, if reading crossed half-way down.
+ *
+ */
+
+ BUG_ON(transp->backRef >= QP_MAX_QUEUE_PAIRS);
+ CommOS_AddReturnAtomic(&transpTable[transp->backRef].holds, 1);
+ if (CommOS_ReadAtomic(&transp->raiseInline)) {
+ RaiseEvent(&transp->work);
+ } else if (CommOS_ScheduleAIOWork(&transp->work)) {
+ TranspTablePut(transp);
+ }
+ }
+ } else {
+ rc = -1;
+ }
+ /* coverity[deref_after_free] */
+ transp->readSize = 0;
+ return rc;
+}
+
+
+/**
+ * @brief Notify any registered listeners for the given queue pair
+ * @param notificationCenterID noop, unused on MVP
+ * @param transpArgs initialization arguments used by the guest for this
+ * channel
+ * @sideeffects the host may attach to the queue pair
+ */
+
+int
+CommTransp_Notify(const CommTranspID *notificationCenterID,
+ CommTranspInitArgs *transpArgs)
+{
+ QPInitArgs args;
+
+ args.id.context = transpArgs->id.d32[0];
+ args.id.resource = transpArgs->id.d32[1];
+ args.capacity = transpArgs->capacity;
+ args.type = transpArgs->type;
+
+ CommOS_Debug(("%s: d32[0]: %u d32[1]: %u\n",
+ __FUNCTION__,
+ transpArgs->id.d32[0],
+ transpArgs->id.d32[1]));
+ QP_Notify(&args);
+ return 0;
+}
diff --git a/arch/arm/mvp/commkm/fatalerror.h b/arch/arm/mvp/commkm/fatalerror.h
new file mode 100644
index 0000000..9676ff3
--- /dev/null
+++ b/arch/arm/mvp/commkm/fatalerror.h
@@ -0,0 +1,126 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief fatal error handlers. They all post fatal errors regardless of build
+ * type.
+ */
+
+#ifndef _FATALERROR_H
+#define _FATALERROR_H
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_WORKSTATION
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#include "mvp_compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum FECode {
+ FECodeMisc, ///< generic FATAL() call of sorts
+ FECodeOOM, ///< FATAL_OOM() call of sorts
+ FECodeAssert, ///< ASSERT() call of sorts
+ FECodeNR, ///< NOT_REACHED() call of sorts
+ FECodeNI, ///< NOT_IMPLEMENTED() call of sorts
+ FECodeNT, ///< NOT_TESTED() call of sorts
+ FECodeCF ///< COMPILE_FAIL() call of sorts
+};
+typedef enum FECode FECode;
+
+#define FATAL() FatalError(__FILE__, __LINE__, FECodeMisc, 0, NULL)
+#define FATAL_IF(x) do { if (UNLIKELY(x)) FATAL(); } while (0)
+#define FATAL_OOM() FatalError(__FILE__, __LINE__, FECodeOOM, 0, NULL)
+#define FATAL_OOM_IF(x) do { if (UNLIKELY(x)) FATAL_OOM(); } while (0)
+
+extern _Bool FatalError_hit;
+
+void NORETURN FatalError(char const *file,
+ int line,
+ FECode feCode,
+ int bugno,
+ char const *fmt,
+ ...) FORMAT(printf,5,6);
+
+#define FATALERROR_COMMON(printFunc, \
+ printFuncV, \
+ file, \
+ line, \
+ feCode, \
+ bugno, \
+ fmt) { \
+ va_list ap; \
+ \
+ printFunc("FatalError: %s:%d, code %d, bugno %d\n", \
+ file, line, feCode, bugno); \
+ if (fmt != NULL) { \
+ va_start(ap, fmt); \
+ printFuncV(fmt, ap); \
+ va_end(ap); \
+ } \
+ }
+
+#if defined IN_HOSTUSER || defined IN_GUESTUSER || defined IN_WORKSTATION
+
+#define FATALERROR_POSIX_USER \
+void \
+FatalError_VErrPrintf(const char *fmt, va_list ap) \
+{ \
+ vfprintf(stderr, fmt, ap); \
+} \
+\
+void \
+FatalError_ErrPrintf(const char *fmt, ...) \
+{ \
+ va_list ap; \
+ va_start(ap, fmt); \
+ FatalError_VErrPrintf(fmt, ap); \
+ va_end(ap); \
+} \
+\
+void NORETURN \
+FatalError(char const *file, \
+ int line, \
+ FECode feCode, \
+ int bugno, \
+ const char *fmt, \
+ ...) \
+{ \
+ FATALERROR_COMMON(FatalError_ErrPrintf, FatalError_VErrPrintf, file, line, feCode, bugno, fmt); \
+ exit(EXIT_FAILURE); \
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/arch/arm/mvp/commkm/include_check.h b/arch/arm/mvp/commkm/include_check.h
new file mode 100644
index 0000000..2eeafe7
--- /dev/null
+++ b/arch/arm/mvp/commkm/include_check.h
@@ -0,0 +1,18 @@
+/*
+ * Linux 2.6.32 and later Kernel module for Empty File Placeholder
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
diff --git a/arch/arm/mvp/commkm/mksck.h b/arch/arm/mvp/commkm/mksck.h
new file mode 100644
index 0000000..e9e10bc
--- /dev/null
+++ b/arch/arm/mvp/commkm/mksck.h
@@ -0,0 +1,153 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+#ifndef _MKSCK_H
+#define _MKSCK_H
+
+/**
+ * @file
+ *
+ * @brief The monitor-kernel socket interface definitions.
+ *
+ * The monitor kernel socket interface was created for (what the name
+ * says) communications between the monitor and host processes. On the
+ * monitor side a special API is introduced, see mksck_vmm.h. On the
+ * host side the API is the standard Berkeley socket interface. Host
+ * process to host process or monitor to monitor communication is not
+ * supported.
+ *
+ * A generic address consists of two 16 bit fields: the vm id and the
+ * port id. Both hosts (vmx) and monitors (vmm) get their vm id
+ * automatically. The host vm id is assigned at the time the host
+ * process opens the mvpkm file descriptor, while the monitor vm id is
+ * assigned when the vmx.c:SetupWorldSwitchPage() calls
+ * Mvpkm_SetupIds(). As a vmx may create multiple monitors to service
+ * an MP guest, a vmx vm id may be associated with multiple monitor vm
+ * ids. A monitor id, however, has a single associated vmx host id,
+ * the id of its canonical vmx.
+ *
+ * Sockets on the host get their addresses either by explicit user
+ * call (the bind command) or implicitly by (issuing a send command
+ * first). At an explicit bind the user may omit one or both fields by
+ * providing MKSCK_VMID_UNDEF/MKSCK_PORT_UNDEF respectively. An
+ * implicit bind behaves as if both fields were omitted in an explicit
+ * bind. The default value of the vmid field is the vmid computed from
+ * the thread group id while that of a port is a new number. It is not
+ * invalid to bind a host process socket with a vm id different from
+ * the vmid computed from the tgid.
+ *
+ * Sockets of the monitor are automatically assigned a vmid, that of their
+ * monitor, at the time of their creation. The port id can be assigned by the
+ * user or left to the implementation to assign an unused one (by specifying
+ * MKSCK_PORT_UNDEF at @ref Mksck_Open).
+ *
+ * Host unconnected sockets may receive from any monitor sender, may send to any
+ * monitor socket. A socket can be connected to a peer address, that enables the
+ * use of the send command.
+ *
+ * One of many special predefined port (both host and monitor) is
+ * MKSCK_PORT_MASTER. It is used for initialization.
+ *
+ * Monitor sockets have to send their peer address explicitly (by
+ * Mksck_SetPeer()) or implicitly by receiving first. After the peer
+ * is set, monitor sockets may send or receive only to/from their
+ * peer.
+ */
+
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#include "vmid.h"
+
+/*
+ * The interface limits the size of transferable packets.
+ */
+#define MKSCK_XFER_MAX 1024
+
+#define MKSCK_ADDR_UNDEF (uint32)0xffffffff
+
+#define MKSCK_PORT_UNDEF (uint16)0xffff
+#define MKSCK_PORT_MASTER (MKSCK_PORT_UNDEF-1)
+#define MKSCK_PORT_HOST_FB (MKSCK_PORT_UNDEF-2)
+#define MKSCK_PORT_BALLOON (MKSCK_PORT_UNDEF-3)
+#define MKSCK_PORT_HOST_HID (MKSCK_PORT_UNDEF-4)
+#define MKSCK_PORT_CHECKPOINT (MKSCK_PORT_UNDEF-5)
+#define MKSCK_PORT_COMM_EV (MKSCK_PORT_UNDEF-6)
+#define MKSCK_PORT_HIGH (MKSCK_PORT_UNDEF-7)
+
+#define MKSCK_VMID_UNDEF VMID_UNDEF
+#define MKSCK_VMID_HIGH (MKSCK_VMID_UNDEF-1)
+
+#define MKSCK_DETACH 3
+
+typedef uint16 Mksck_Port;
+typedef VmId Mksck_VmId;
+
+/**
+ * @brief Page descriptor for typed messages. Each page describes a region of
+ * the machine address space with base mpn and size 2^(12 + order) bytes.
+ */
+typedef struct {
+ uint32 mpn : 20; ///< Base MPN of region described by page
+ uint32 order : 12; ///< Region is 2^(12 + order) bytes.
+} Mksck_PageDesc;
+
+/**
+ * @brief Typed message template macro. Allows us to avoid having two message
+ * types, one with page descriptor vector (for VMM), one without (for
+ * VMX).
+ *
+ * @param type C type of uninterpreted component of the message (following the
+ * page descriptor vector).
+ * @param pages number of page descriptors in vector.
+ */
+#define MKSCK_DESC_TYPE(type,pages) \
+ struct { \
+ type umsg; \
+ Mksck_PageDesc page[pages]; \
+ }
+
+/**
+ * @brief The monitor kernel socket interface address format
+ */
+typedef union {
+ uint32 addr; ///< the address
+ struct { /* The address is decomposed to two shorts */
+ Mksck_Port port; ///< port unique within a vmid
+ Mksck_VmId vmId; ///< unique vmid
+ };
+} Mksck_Address;
+
+static inline uint32
+Mksck_AddrInit(Mksck_VmId vmId, Mksck_Port port)
+{
+ Mksck_Address aa;
+ aa.vmId = vmId;
+ aa.port = port;
+ return aa.addr;
+}
+#endif
diff --git a/arch/arm/mvp/commkm/mksck_sockaddr.h b/arch/arm/mvp/commkm/mksck_sockaddr.h
new file mode 100644
index 0000000..82df240
--- /dev/null
+++ b/arch/arm/mvp/commkm/mksck_sockaddr.h
@@ -0,0 +1,50 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Host user space definitions for mksck sockets.
+ */
+
+#ifndef _MKSCK_SOCKADDR_H_
+#define _MKSCK_SOCKADDR_H_
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#include "mksck.h"
+
+/* no one ever uses DECnet anymore? */
+#define AF_MKSCK AF_DECnet
+#define PF_MKSCK PF_DECnet
+
+/* Address structure used by the host user socket interface. */
+struct sockaddr_mk {
+ sa_family_t mk_family;
+ Mksck_Address mk_addr;
+};
+
+#endif
diff --git a/arch/arm/mvp/commkm/mvp.h b/arch/arm/mvp/commkm/mvp.h
new file mode 100644
index 0000000..a57f8cc
--- /dev/null
+++ b/arch/arm/mvp/commkm/mvp.h
@@ -0,0 +1,48 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief top-level include for all basic includes.
+ * This file should not define anything of its own.
+ */
+
+#ifndef _MVP_H
+#define _MVP_H
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_WORKSTATION
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#include "mvp_compiler.h"
+#include "utils.h"
+#include "mvp_assert.h"
+#include "mvp_types.h"
+#include "platdefx.h"
+
+#endif
diff --git a/arch/arm/mvp/commkm/mvp_assert.h b/arch/arm/mvp/commkm/mvp_assert.h
new file mode 100644
index 0000000..cbc5ed8
--- /dev/null
+++ b/arch/arm/mvp/commkm/mvp_assert.h
@@ -0,0 +1,125 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief ASSERT() and related macros.
+ */
+
+#ifndef _MVP_ASSERT_H
+#define _MVP_ASSERT_H
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_WORKSTATION
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#define ASSERT(_x) ASSERT_BUG((_x),0)
+
+#ifndef NDEBUG
+#define ASSERT_BUG(_x,_tkt) do { \
+ if (UNLIKELY(!(_x))) { \
+ FatalError(__FILE__, __LINE__, FECodeAssert, _tkt, NULL); \
+ } \
+} while (0)
+
+#define ASSERTF(_x, ...) do { \
+ if (UNLIKELY(!(_x))) { \
+ FatalError(__FILE__, \
+ __LINE__, \
+ FECodeAssert, \
+ 0, \
+ __VA_ARGS__); \
+ } \
+} while (0)
+#else
+
+#define ASSERT_BUG(_x,_tkt) (void)sizeof((int)(_x))
+#define ASSERTF(_x, ...) ASSERT_BUG(_x, 0)
+
+#endif
+
+/*
+ * Compile-time assertions.
+ *
+ * ASSERT_ON_COMPILE does not use the common
+ * switch (0) { case 0: case (e): ; } trick because some compilers (e.g. MSVC)
+ * generate code for it.
+ *
+ * The implementation uses both enum and typedef because the typedef alone is
+ * insufficient; gcc allows arrays to be declared with non-constant expressions
+ * (even in typedefs, where it makes no sense).
+ */
+#ifdef __COVERITY__
+#define ASSERT_ON_COMPILE(e) ASSERT(e)
+#else
+#define ASSERT_ON_COMPILE(e) \
+ do { \
+ enum { AssertOnCompileMisused = ((e) ? 1 : -1) }; \
+ typedef char AssertOnCompileFailed[AssertOnCompileMisused]; \
+ } while (0)
+#endif
+
+/*
+ * To put an ASSERT_ON_COMPILE() outside a function, wrap it
+ * in MY_ASSERTS(). The first parameter must be unique in
+ * each .c file where it appears. For example,
+ *
+ * MY_ASSERTS(FS3_INT,
+ * ASSERT_ON_COMPILE(sizeof(FS3_DiskLock) == 128);
+ * ASSERT_ON_COMPILE(sizeof(FS3_DiskLockReserved) == DISK_BLOCK_SIZE);
+ * ASSERT_ON_COMPILE(sizeof(FS3_DiskBlock) == DISK_BLOCK_SIZE);
+ * ASSERT_ON_COMPILE(sizeof(Hardware_DMIUUID) == 16);
+ * )
+ *
+ * Caution: ASSERT() within MY_ASSERTS() is silently ignored.
+ * The same goes for anything else not evaluated at compile time.
+ */
+
+#define MY_ASSERTS(name, assertions) \
+ static inline void name(void) { \
+ assertions \
+ }
+
+#define KNOWN_BUG(_tkt)
+
+#define NOT_IMPLEMENTED() NOT_IMPLEMENTED_JIRA(0)
+#define NOT_IMPLEMENTED_JIRA(_tkt,...) FatalError(__FILE__, __LINE__, FECodeNI, _tkt, NULL)
+
+#define NOT_IMPLEMENTED_IF(_x) NOT_IMPLEMENTED_IF_JIRA((_x),0)
+#define NOT_IMPLEMENTED_IF_JIRA(_x,_tkt,...) do { if (UNLIKELY(_x)) NOT_IMPLEMENTED_JIRA(_tkt); } while (0)
+/*
+ * All sites tagged with this are @knownjira{MVP-1855}.
+ */
+#define NOT_IMPLEMENTEDF(...) FatalError(__FILE__, __LINE__, FECodeNI, 0, __VA_ARGS__)
+
+#define NOT_REACHED() FatalError(__FILE__, __LINE__, FECodeNR, 0, NULL)
+
+#include "fatalerror.h"
+#include "nottested.h"
+
+#endif
diff --git a/arch/arm/mvp/commkm/mvp_compiler.h b/arch/arm/mvp/commkm/mvp_compiler.h
new file mode 100644
index 0000000..21af455
--- /dev/null
+++ b/arch/arm/mvp/commkm/mvp_compiler.h
@@ -0,0 +1,56 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Compiler-related definitions and directives.
+ */
+
+#ifndef _MVP_COMPILER_H_
+#define _MVP_COMPILER_H_
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_WORKSTATION
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#ifdef __GNUC__
+#include "mvp_compiler_gcc.h"
+#else /* __GNUC__ */
+#include "mvp_compiler_other.h"
+#endif /* __GNUC__ */
+
+/**
+ * @brief Find last set bit.
+ *
+ * @param n unsigned 32-bit integer.
+ *
+ * @return 0 if n == 0 otherwise 32 - the number of leading zeroes in n.
+ */
+#define FLS(n) (32 - CLZ(n))
+
+#endif /// ifndef _MVP_COMPILER_H_
diff --git a/arch/arm/mvp/commkm/mvp_compiler_gcc.h b/arch/arm/mvp/commkm/mvp_compiler_gcc.h
new file mode 100644
index 0000000..fbc96e3
--- /dev/null
+++ b/arch/arm/mvp/commkm/mvp_compiler_gcc.h
@@ -0,0 +1,87 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief common definitions for GCC
+ */
+
+#ifndef _MVP_COMPILER_GCC_H
+#define _MVP_COMPILER_GCC_H
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_WORKSTATION
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+/**
+ * @brief Count leading zeroes.
+ *
+ * @param n unsigned 32-bit integer.
+ *
+ * @return 32 if n == 0 otherwise 31 - the bit position of the most significant 1
+ * in n.
+ */
+#ifdef __COVERITY__
+static inline int
+CLZ(unsigned int n)
+{
+ unsigned int r = 0;
+
+ while (n) {
+ r++;
+ n >>= 1;
+ }
+
+ return 32 - r;
+}
+#else
+#define CLZ(n) __builtin_clz(n)
+#endif
+
+#define PACKED __attribute__ ((packed))
+#define ALLOC __attribute__ ((malloc, warn_unused_result))
+#define UNUSED __attribute__ ((unused))
+#define PURE __attribute__ ((pure))
+#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
+#define FORMAT(x,y,z) __attribute__ ((format(x,y,z)))
+#define LIKELY(x) __builtin_expect(!!(x), 1)
+#define UNLIKELY(x) __builtin_expect((x), 0)
+
+/*
+ * For debug builds, we want to omit __attribute__((noreturn)) so that gcc will
+ * keep stack linkages and then we will have useful core dumps. For non-debug
+ * builds, we don't care about the stack frames and want the little bit of
+ * optimization that noreturn gives us.
+ */
+#if defined(__COVERITY__) || !defined(MVP_DEBUG)
+#define NORETURN __attribute__((noreturn))
+#else
+#define NORETURN
+#endif
+
+#endif
diff --git a/arch/arm/mvp/commkm/mvp_types.h b/arch/arm/mvp/commkm/mvp_types.h
new file mode 100644
index 0000000..ba5c04c
--- /dev/null
+++ b/arch/arm/mvp/commkm/mvp_types.h
@@ -0,0 +1,94 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief basic type definitions.
+ * These may need to be conditionalized for different compilers/platforms.
+ */
+
+#ifndef _MVPTYPES_H
+#define _MVPTYPES_H
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_WORKSTATION
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef unsigned long long uint64;
+
+typedef signed char int8;
+typedef short int16;
+typedef int int32;
+typedef long long int64;
+
+typedef uint32 CVA; // whatever we are compiling the code as
+typedef uint32 GVA; // guest virtual addresses
+typedef uint32 MVA; // monitor virtual addresses
+typedef uint32 HKVA; // host kernel virtual addresses
+typedef uint32 HUVA; // host user virtual addresses
+typedef uint64 PA; // (guest) physical addresses (40-bit)
+typedef uint32 MA; // (host) machine addresses
+
+typedef uint32 PPN; // PA/PAGE_SIZE
+typedef uint32 MPN; // MA/PAGE_SIZE
+
+typedef uint64 cycle_t;
+
+/**
+ * @brief Page segment.
+ *
+ * Specifies a segment within a single page.
+ */
+typedef struct {
+ uint16 off;
+ uint16 len;
+} PageSeg;
+
+/*
+ * GCC's argument checking for printf-like functions
+ *
+ * fmtPos is the position of the format string argument, beginning at 1
+ * varPos is the position of the variable argument, beginning at 1
+ */
+
+#if defined(__GNUC__)
+# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos)))
+#else
+# define PRINTF_DECL(fmtPos, varPos)
+#endif
+
+#if defined(__GNUC__)
+# define SCANF_DECL(fmtPos, varPos) __attribute__((__format__(__scanf__, fmtPos, varPos)))
+#else
+# define SCANF_DECL(fmtPos, varPos)
+#endif
+
+#endif /* _MVPTYPES_H */
diff --git a/arch/arm/mvp/commkm/mvpkm_comm_ev.h b/arch/arm/mvp/commkm/mvpkm_comm_ev.h
new file mode 100644
index 0000000..b220a9b
--- /dev/null
+++ b/arch/arm/mvp/commkm/mvpkm_comm_ev.h
@@ -0,0 +1,53 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief mvpkm kernel hooks for comm event signaling
+ */
+
+#ifndef _MVPKM_COMM_EV_H
+#define _MVPKM_COMM_EV_H
+
+extern int (*CommTranspEvProcess)(CommTranspID* id, CommTranspIOEvent event);
+
+/**
+ * @brief Forward any guest signal requests to the commkm module
+ * @param id transport channel id
+ * @param event comm event type
+ */
+
+static inline void
+Mvpkm_CommEvSignal(CommTranspID *id, CommTranspIOEvent event)
+{
+ if (CommTranspEvProcess) {
+ CommTranspEvProcess(id, event);
+ }
+}
+
+void
+Mvpkm_CommEvRegisterProcessCB(int (*commProcessFunc)(CommTranspID*,
+ CommTranspIOEvent));
+void Mvpkm_CommEvUnregisterProcessCB(void);
+
+
+
+#endif
diff --git a/arch/arm/mvp/commkm/nottested.h b/arch/arm/mvp/commkm/nottested.h
new file mode 100644
index 0000000..c5c1e26
--- /dev/null
+++ b/arch/arm/mvp/commkm/nottested.h
@@ -0,0 +1,54 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief NOT_TESTED() and related.
+ */
+
+#ifndef _NOTTESTED_H
+#define _NOTTESTED_H
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_WORKSTATION
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#include <stdbool.h>
+
+#ifdef NOT_TESTED_ENABLED
+#define NotTestedEnabled true
+#else
+#define NotTestedEnabled false
+#endif
+
+#define NOT_TESTED() NOT_TESTED_JIRA(0)
+#define NOT_TESTED_JIRA(_tkt,...) NotTested(_tkt, __FILE__, __LINE__)
+
+void NotTested(int tkt, char const *file, int line);
+
+#endif
diff --git a/arch/arm/mvp/commkm/platdefx.h b/arch/arm/mvp/commkm/platdefx.h
new file mode 100644
index 0000000..42953e6
--- /dev/null
+++ b/arch/arm/mvp/commkm/platdefx.h
@@ -0,0 +1,67 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief Basic platform definitions needed various places.
+ */
+
+#ifndef _PLATDEFX_H
+#define _PLATDEFX_H
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_WORKSTATION
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#define PAGE_ORDER 12
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE (1UL << PAGE_ORDER)
+#endif
+#if PAGE_SIZE != 4096
+#error bad page size PAGE_SIZE
+#endif
+
+#define PA_2_PPN(_pa) ((_pa) / PAGE_SIZE)
+#define PPN_2_PA(_ppn) ((_ppn) * PAGE_SIZE)
+
+#define VMM_DOMAIN 0x0
+#define VMM_DOMAIN_NO_ACCESS 0x3
+#define VMM_DOMAIN_CLIENT 0x1
+#define VMM_DOMAIN_MANAGER 0x4
+
+#define INVALID_CVA (-(CVA)1)
+#define INVALID_GVA (-(GVA)1)
+#define INVALID_MVA (-(MVA)1)
+#define INVALID_HKVA (-(HKVA)1)
+#define INVALID_HUVA (-(HUVA)1)
+
+#define INVALID_MPN (((MPN)-1) >> ARM_L2D_SMALL_ORDER)
+#define INVALID_PPN (((PPN)-1) >> ARM_L2D_SMALL_ORDER)
+
+#endif
diff --git a/arch/arm/mvp/commkm/qp.h b/arch/arm/mvp/commkm/qp.h
new file mode 100644
index 0000000..d4a50ec
--- /dev/null
+++ b/arch/arm/mvp/commkm/qp.h
@@ -0,0 +1,332 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief MVP Queue Pairs function and structure declarations
+ *
+ * MVP Queue Pairs:
+ *
+ * Queue pairs are intended to be a generic bulk data transport mechanism
+ * between the guest and host kernels. The queue pair abstraction is based
+ * on two ring buffers (queues) placed on a shared memory region mapped
+ * into both guest and host kernel address spaces.
+ *
+ * NOTE: Queue pairs are SINGLE-READER, SINGLE-WRITER. Any caller is
+ * responsible for multi-reader/writer serialization!!!
+ *
+ * There are a maximum of QP_MAX_QUEUE_PAIRS in the system, with a maximum
+ * size of QP_MAX_CAPACITY per pair. Each queue pair is identified by
+ * an ID.
+ *
+ * Each peer follows a producer-consumer model in which one side is the
+ * producer on one queue, and the other side is the consumer on that queue
+ * (and vice-versa for its pair).
+ *
+ * Data is enqueued and dequeued into the pair in transactional stages,
+ * meaning each enqueue/dequeue can be followed by zero or more
+ * enqueue/dequeues, but the enqueue/dequeue is not visible to the peer
+ * until it has been committed with the *Commit() function.
+ * In PVTCP, for example, this is used to enqueue a short header, then
+ * followed by 'segments' of iovecs, then followed by a commit. This
+ * model prevents a peer from reading the header, expecting a payload,
+ * but not being able to read the payload because it hasn't been
+ * enqueued yet.
+ *
+ * Queue Pair setup:
+ *
+ * Before data can be passed, the guest and host kernel must perform
+ * the following connection handshake:
+ *
+ * 1). A host kernel service registers a listener with the queue pair
+ * subsystem with a callback to be called when guests create
+ * and attach to a shared memory region.
+ *
+ * 2). Guest initiates an QP_Attach() operation to a shared memory region
+ * keyed by ID. This step allocates memory, maps it into the host
+ * address space, and optionally notifies any host services who are
+ * listening for attach requests from the guest (see previous step).
+ * Host listeners are provided with a copy of the initialization
+ * arguments used by the guest (id, size, service type). All registered
+ * listeners are iterated over until one of them handles the attach
+ * request and acknowledges with QP_SUCCESS.
+ *
+ * 3). The registered host callback is called, notifying the host that
+ * the guest has attached.
+ *
+ * 4). The host can now QP_Attach() to the shared memory region with the same
+ * arguments as the guest. The queue pair is now well formed and enqueues
+ * and dequeues can proceed on either side.
+ *
+ * Queue Pair teardown:
+ *
+ * 1). As before, teardowns are initiated by the guest. Hosts can register
+ * a callback to be called upon detach. Guests initiate a teardown
+ * through a call to QP_Detach().
+ *
+ * 2). Registered hosts are notified through the aforementioned callback.
+ * 3). The host service can call QP_Detach() at its own leisure. Memory
+ * is freed, the queue pair is destroyed.
+ *
+ * If at any point the guest unexpectedly shuts down, the host will be
+ * notified at monitor shutdown time. Memory is freed, and the queue
+ * pair is destroyed.
+ *
+ */
+
+#ifndef _QP_H
+#define _QP_H
+
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+//#define QP_DEBUG 1
+
+typedef enum QPState {
+ QP_STATE_FREE = 0x1, ///< No peers, not memory-backed
+ QP_STATE_CONNECTED, ///< Both peers attached , memory backed
+ QP_STATE_GUEST_ATTACHED, ///< Guest allocated memory, host not yet attached
+ QP_STATE_MAX // leave this at the end!
+} QPState;
+
+typedef struct QPId {
+ uint32 context;
+ uint32 resource;
+} QPId;
+
+/*
+ * Initialization arguments for each queue pair
+ */
+typedef struct QPInitArgs {
+ QPId id; ///< Shared memory region ID
+ uint32 capacity; ///< Total size of shared region in bytes
+ uint32 type; ///< Type of queue pair (PVTCP, other)...
+} QPInitArgs;
+
+/*
+ * Placed on the shared region, two per region
+ */
+typedef struct QHandle {
+ volatile uint32 head; ///< queue head offset
+ volatile uint32 tail; ///< queue tail offset
+ volatile uint32 phantom_head; ///< queue shadow head offset
+ volatile uint32 phantom_tail; ///< queue shadow tail offset
+ uint8 data[0]; ///< start of data, runs off
+ // the struct
+} QHandle;
+
+/*
+ * Local to each peer
+ */
+typedef struct QPHandle {
+ QPId id; ///< shared memory region ID
+ uint32 capacity; ///< size of region in bytes
+ QHandle *produceQ; ///< producer queue
+ QHandle *consumeQ; ///< consumer queue
+ uint32 queueSize; ///< size of each queue in bytes
+ uint32 type; ///< type of queue pair
+
+ /*
+ * Following fields unused by guest
+ */
+ QPState state;
+ void (*peerDetachCB)(void* data); ///< detach notification callback
+ void *detachData; ///< data for the detach cb
+ struct page **pages; ///< page pointers for shared region
+} QPHandle;
+
+/*
+ * QP Error codes
+ */
+#define QP_SUCCESS 0
+#define QP_ERROR_NO_MEM (-1)
+#define QP_ERROR_INVALID_HANDLE (-2)
+#define QP_ERROR_INVALID_ARGS (-3)
+#define QP_ERROR_ALREADY_ATTACHED (-4)
+
+/*
+ * Hard-coded limits
+ */
+#define QP_MIN_CAPACITY (PAGE_SIZE * 2)
+#define QP_MAX_CAPACITY (1024*1024) // 1M
+#define QP_MAX_QUEUE_PAIRS 32
+#define QP_MAX_ID QP_MAX_QUEUE_PAIRS
+#define QP_MAX_LISTENERS QP_MAX_QUEUE_PAIRS
+#define QP_MAX_PAGES (QP_MAX_CAPACITY/PAGE_SIZE) // 256 pages
+
+#define QP_INVALID_ID 0xFFFFFFFF
+#define QP_INVALID_SIZE 0xFFFFFFFF
+#define QP_INVALID_REGION 0xFFFFFFFF
+#define QP_INVALID_TYPE 0xFFFFFFFF
+
+#ifdef __KERNEL__
+/**
+ * @brief Utility function to sanity check arguments
+ * @param args argument structure to check
+ * @return true if arguments are sane, false otherwise
+ */
+static inline
+_Bool QP_CheckArgs(QPInitArgs *args)
+{
+ if (!args ||
+ !is_power_of_2(args->capacity) ||
+ (args->capacity < QP_MIN_CAPACITY) ||
+ (args->capacity > QP_MAX_CAPACITY) ||
+ !(args->id.resource < QP_MAX_ID || args->id.resource == QP_INVALID_ID) ||
+ (args->type == QP_INVALID_TYPE)) {
+ return false;
+ } else {
+ return true;
+ }
+}
+#endif
+
+
+/**
+ * @brief Utility function to sanity check a queue pair handle
+ * @param qp handle to the queue pair
+ * @return true if the handle is sane, false otherwise
+ */
+static inline
+_Bool QP_CheckHandle(QPHandle *qp)
+{
+#ifdef MVP_DEBUG
+ if (!(qp) ||
+ !(qp->produceQ) ||
+ !(qp->consumeQ) ||
+ (qp->state >= (uint32)QP_STATE_MAX) ||
+ !(qp->queueSize < (QP_MAX_CAPACITY/2))) {
+ return false;
+ } else {
+ return true;
+ }
+#else
+ return true;
+#endif
+}
+
+
+/**
+ * @brief Initializes an invalid handle
+ * @param[in, out] qp handle to the queue pair
+ */
+static inline void
+QP_MakeInvalidQPHandle(QPHandle *qp)
+{
+ if (!qp) {
+ return;
+ }
+
+ qp->id.context = QP_INVALID_ID;
+ qp->id.resource = QP_INVALID_ID;
+ qp->capacity = QP_INVALID_SIZE;
+ qp->produceQ = NULL;
+ qp->consumeQ = NULL;
+ qp->queueSize = QP_INVALID_SIZE;
+ qp->type = QP_INVALID_TYPE;
+ qp->state = QP_STATE_FREE;
+ qp->peerDetachCB = NULL;
+ qp->detachData = NULL;
+}
+
+/*
+ * Host only
+ */
+typedef int32 (*QPListener)(const QPInitArgs*);
+int32 QP_RegisterListener(const QPListener);
+int32 QP_UnregisterListener(const QPListener);
+int32 QP_RegisterDetachCB(QPHandle *qp, void (*callback)(void*), void *data);
+
+
+/*
+ * Host and guest specific implementations, see qp_host.c and qp_guest.c
+ */
+int32 QP_Attach(QPInitArgs *args, QPHandle** qp);
+int32 QP_Detach(QPHandle* qp);
+int32 QP_Notify(QPInitArgs *args);
+
+/*
+ * Common implementation, see qp_common.c
+ */
+int32 QP_EnqueueSpace(QPHandle *qp);
+int32 QP_EnqueueSegment(QPHandle *qp, const void *buf, size_t length);
+int32 QP_EnqueueCommit(QPHandle *qp);
+int32 QP_EnqueueReset(QPHandle *qp);
+
+static inline int32
+QP_EnqueueAtomic(QPHandle *qp, const void *buf, size_t length)
+{
+ int32 rc;
+ QP_EnqueueReset(qp);
+ rc = QP_EnqueueSegment(qp, buf, length);
+ if (rc < 0) {
+ return rc;
+ } else {
+ QP_EnqueueCommit(qp);
+ }
+ return rc;
+}
+
+int32 QP_DequeueSpace(QPHandle *qp);
+int32 QP_DequeueSegment(QPHandle *qp, const void *buf, size_t length);
+int32 QP_DequeueReset(QPHandle *qp);
+int32 QP_DequeueCommit(QPHandle *qp);
+
+static inline int32
+QP_DequeueAtomic(QPHandle *qp, const void *buf, size_t length)
+{
+ int32 rc;
+ QP_DequeueReset(qp);
+ rc = QP_DequeueSegment(qp, buf, length);
+ if (rc < 0) {
+ return rc;
+ } else {
+ QP_DequeueCommit(qp);
+ }
+ return rc;
+}
+
+/*
+ * HVC methods and signatures
+ */
+#define MVP_QP_SIGNATURE 0x53525051 ///< 'QPRS'
+#define MVP_QP_ATTACH (MVP_OBJECT_CUSTOM_BASE + 0) ///< attach to a queue pair
+#define MVP_QP_DETACH (MVP_OBJECT_CUSTOM_BASE + 1) ///< detach from a queue pair
+#define MVP_QP_NOTIFY (MVP_OBJECT_CUSTOM_BASE + 2) ///< notify host of attach
+#define MVP_QP_LAST (MVP_OBJECT_CUSTOM_BASE + 3) ///< Number of methods
+
+/*
+ * Debug macros
+ */
+#ifdef QP_DEBUG
+ #ifdef IN_MONITOR
+ #define QP_DBG(...) Log(__VA_ARGS__)
+ #else
+ #define QP_DBG(...) printk(KERN_INFO __VA_ARGS__)
+ #endif
+#else
+ #define QP_DBG(...)
+#endif
+
+#endif
diff --git a/arch/arm/mvp/commkm/utils.h b/arch/arm/mvp/commkm/utils.h
new file mode 100644
index 0000000..b5f1e18
--- /dev/null
+++ b/arch/arm/mvp/commkm/utils.h
@@ -0,0 +1,172 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+/**
+ * @file
+ *
+ * @brief General architecture-independent definitions, typedefs, and macros.
+ */
+
+#ifndef _UTILS_H
+#define _UTILS_H
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_PV
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_WORKSTATION
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#define MAX_FILENAME 128
+
+// Round address up to given size boundary
+// Note: ALIGN() conflicts with Linux
+
+#define MVP_ALIGN(_v, _n) (((_v) + (_n) - 1) & -(_n))
+
+#define ALIGNVA(_addr, _size) MVP_ALIGN(_addr, _size)
+
+#define alignof(t) offsetof(struct { char c; typeof(t) x; }, x)
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define KB(_X_) ((_X_)*1024U)
+#define MB(_X_) (KB(_X_)*1024)
+#define GB(_X_) (MB(_X_)*1024)
+
+#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
+
+/*
+ * x in [low,high)
+ * args evaluated once
+ */
+#define RANGE(x,low,high) \
+ ({ \
+ typeof(x) _x = (x); \
+ typeof(x) _low = (typeof(x))(low); \
+ typeof(x) _high =(typeof(x))(high); \
+ (_Bool)( (_low <= _x) && (_x < _high)); \
+ })
+
+#define OBJECTS_PER_PAGE(_type) (PAGE_SIZE / sizeof(_type))
+
+#define MA_2_MPN(_ma) ((MPN)((_ma) / PAGE_SIZE))
+#define MPN_2_MA(_mpn) ((MA)((_mpn) * PAGE_SIZE))
+
+#define VA_2_VPN(_va) ((_va) / PAGE_SIZE)
+#define VPN_2_vA(_vpn) ((_vpn) * PAGE_SIZE)
+
+/*
+ * The following convenience macro can be used in a following situation
+ *
+ * send(..., &foo, sizeof(foo)) --> send(..., PTR_N_SIZE(foo))
+ */
+
+#define PTR_N_SIZE(_var) &(_var), sizeof(_var)
+
+
+/*
+ *
+ * BIT-PULLING macros
+ *
+ */
+#define MVP_BIT(val,n) ( ((val)>>(n))&1)
+#define MVP_BITS(val,m,n) (((val)<<(31-(n))) >> ((31-(n))+(m)) )
+#define MVP_EXTRACT_FIELD(w, m, n) MVP_BITS((w), (m), ((m) + (n) - 1))
+#define MVP_MASK(m, n) (MVP_EXTRACT_FIELD(~(uint32)0U, (m), (n)) << (m))
+#define MVP_UPDATE_FIELD(old_val, field_val, m, n) \
+ (((old_val) & ~MVP_MASK((m), (n))) | (MVP_EXTRACT_FIELD((field_val), 0, (n)) << (m)))
+
+/*
+ *
+ * 64BIT-PULLING macros
+ *
+ */
+#define MVP_BITS64(val,m,n) (((val)<<(63-(n))) >> ((63-(n))+(m)) )
+#define MVP_EXTRACT_FIELD64(w, m, n) MVP_BITS64((w), (m), ((m) + (n) - 1))
+#define MVP_MASK64(m, n) (MVP_EXTRACT_FIELD64(~(uint64)0ULL, (m), (n)) << (m))
+#define MVP_UPDATE_FIELD64(old_val, field_val, m, n) \
+ (((old_val) & ~MVP_MASK64((m), (n))) | (MVP_EXTRACT_FIELD64(((uint64)(field_val)), 0ULL, (n)) << (m)))
+
+/*
+ *
+ * BIT-CHANGING macros
+ *
+ */
+#define MVP_SETBIT(val,n) ((val)|=(1<<(n)))
+#define MVP_CLRBIT(val,n) ((val)&=(~(1<<(n))))
+
+/*
+ * Fixed bit-width sign extension.
+ */
+#define MVP_SIGN_EXTEND(val,width) \
+ (((val) ^ (1 << ((width) - 1))) - (1 << ((width) - 1)))
+
+
+/*
+ * Assembler helpers.
+ */
+#define _MVP_HASH #
+#define MVP_HASH() _MVP_HASH
+
+#define _MVP_STRINGIFY(...) #__VA_ARGS__
+#define MVP_STRINGIFY(...) _MVP_STRINGIFY(__VA_ARGS__)
+
+#ifndef __ASSEMBLER__
+
+#include <stddef.h>
+#include <stdbool.h>
+
+/*
+ * Constant equivalents of build-flags.
+ *
+ * Test these when possible instead of using #ifdef so that your code
+ * gets parsed.
+ */
+#ifdef MVP_DEBUG
+static const _Bool mvpDebug = true;
+#else
+static const _Bool mvpDebug = false;
+#endif
+
+#ifdef MVP_STATS
+static const _Bool mvpStats = true;
+#else
+static const _Bool mvpStats = false;
+#endif
+
+#ifdef MVP_DEVEL
+static const _Bool mvpDevel = true;
+#else
+static const _Bool mvpDevel = false;
+#endif
+
+#endif
+
+#endif
diff --git a/arch/arm/mvp/commkm/vmid.h b/arch/arm/mvp/commkm/vmid.h
new file mode 100644
index 0000000..f24a650
--- /dev/null
+++ b/arch/arm/mvp/commkm/vmid.h
@@ -0,0 +1,44 @@
+/*
+ * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications
+ *
+ * Copyright (C) 2010-2012 VMware, Inc. 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 version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#line 5
+
+#ifndef _VMID_H
+#define _VMID_H
+
+/**
+ * @file
+ *
+ * @brief The vmid definition
+ */
+
+
+
+#define INCLUDE_ALLOW_MVPD
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_MONITOR
+#define INCLUDE_ALLOW_HOSTUSER
+#define INCLUDE_ALLOW_GUESTUSER
+#define INCLUDE_ALLOW_GPL
+#include "include_check.h"
+
+#define VMID_UNDEF (uint16)0xffff
+typedef uint16 VmId;
+
+#endif