M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
+340
View File
@@ -0,0 +1,340 @@
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) 19yy <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) 19yy 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.
@@ -0,0 +1,16 @@
KERNEL_FLAGS ?= ARCH=arm
kmake = $(MAKE) $(KERNEL_FLAGS) -C $(KERNEL_DIR) M=$(CURDIR)
all-local:
$(kmake) modules
install-exec-local:
$(kmake) modules_install INSTALL_MOD_PATH=$(DESTDIR)$(prefix)/modules INSTALL_MOD_DIR=kernel-tests
# "make distclean" will always run clean-local in this directory,
# regardless of the KERNELMODULES conditional. Therefore, ensure
# KERNEL_DIR exists before running clean. Further, don't fail even
# if there is a problem.
clean-local:
-test ! -d "$(KERNEL_DIR)" || $(kmake) clean
@@ -0,0 +1,34 @@
ACLOCAL_AMFLAGS = -I m4
topdir = $(prefix)
BUILD_TEST=
if KERNELMODULES
if USEION
BUILD_TEST += ion
endif
if USEMEMORY_PROF
BUILD_TEST += memory_prof
endif
if USEMSM_BUS
BUILD_TEST += msm_bus
endif
if USEWATCHDOG
BUILD_TEST += watchdog
endif
if USEOCMEM
BUILD_TEST += ocmem
endif
endif
if USESPS
BUILD_TEST += sps
endif
if USEV4L2APPS
BUILD_TEST += v4l2apps
endif
SUBDIRS = $(BUILD_TEST)
@@ -0,0 +1,4 @@
# Kernel module make instructions go here.
#
obj-m := xyz_module.o
xyz_module-objs := xyzmod.o
@@ -0,0 +1,25 @@
#
# Rules for building kernel-tests should go in this file.
#
# replace names beginning with 'xyz' with suitable names.
xyzdir = $(prefix)
# See the automake manual for full details of this syntax.
xyz_PROGRAMS = xyzmod
# Uncomment this if your script needs to install the 'common' setup
# script from android.
dist_xyz_SCRIPTS += ../test_env_setup.sh
#-----------------------------------------------------------------------------
# Below this line is automake boilerplate. Casual users should not need
# to go below this line.
PWD := $(shell pwd)
all-local:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
install-exec-local:
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(DESTDIR)$(prefix) modules_install
depmod $(shell cat $(KERNELDIR)/include/config/kernel.release 2> /dev/null) -b $(DESTDIR)$(prefix)
@@ -0,0 +1,32 @@
/* Copyright (c) 2012, The Linux Foundation. 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 and
* only 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.
*/
/*
* A trivial example kernel module.
*/
#include <linux/init.h>
#include <linux/module.h>
static int template_init(void)
{
printk(KERN_ALERT "Hello, world!\n");
return 0;
}
static void template_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world.\n");
}
module_init(template_init);
module_exit(template_exit);
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,70 @@
# _ENABLE_KERNEL_TEST(kernel-test,
# shell-kernel-test
# conditional-kernel-test
# help-string,
# enable-if-not-given
# [additional-checks])
#
# kernel-test: passed directly through to the
# AC_ARG_ENABLE macro as the feature
#
# shell-kernel-test: name of the shell variable that AC_ARG_ENABLE
# creates from kernel-test
#
# conditional-kernel-test: name of the conditional to create
#
# help-string: passed directly through to the AS_HELP_STRING
# macro as the right-hand-side
#
# enable-if-not-given: value used when neither --enable-kernel-test
# nor --disable-kernel-test is given
#
# additional-checks: shell commands run before the AM_CONDITIONAL macro;
# can be used to change the conditional by setting
# the shell variable specified in shell-kernel-test.
# ----------------------------------------------------------------------
AC_DEFUN([_ENABLE_KERNEL_TEST],
[
AC_ARG_ENABLE([$1],
[AS_HELP_STRING([--enable-$1],[$4])],
[case "${$2}" in
yes|no) ;;
*) AC_MSG_ERROR([bad value '${$2}' for --enable-$1]) ;;
esac],
[$2=$5]
)
$6
AM_CONDITIONAL([$3],[test "x${$2}" = "xyes"])
]
)
# ENABLE_KERNEL_TEST(kernel-test,
# help-string,
# [enable-if-not-given = yes]
# [additional-checks])
#
# kernel-test: passed directly through to the
# AC_ARG_ENABLE macro as the feature
#
# help-string: passed directly through to the
# AS_HELP_STRING macro as the right-hand-side
#
# enable-if-not-given: value used when neither --enable-kernel-test
# nor --disable-kernel-test is given
#
# additional-checks: shell commands run before the AM_CONDITIONAL macro;
# can be used to change the conditional by setting
# the shell variable named enable_<kernel-test>, with
# any dashes and dots in kernel-test changed into '_'.
# -----------------------------------------------------------------------
AC_DEFUN([ENABLE_KERNEL_TEST],
[
_ENABLE_KERNEL_TEST([$1],
m4_join([],[enable_],m4_translit([$1],[-.],[__])),
m4_join([],[USE],m4_toupper(m4_translit([$1],[-.],[__]))),
[$2],
m4_ifnblank([$3],[$3],[yes]),
[$4]
)
]
)
+10
View File
@@ -0,0 +1,10 @@
#!/bin/sh
# autogen.sh -- Autotools bootstrapping
#
aclocal &&\
autoheader &&\
autoconf &&\
automake --add-missing --copy
@@ -0,0 +1,11 @@
ifeq ($(call is-vendor-board-platform,QCOM),true)
DLKM_DIR := device/qcom/common/dlkm
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := bus_timeout_mod.ko
LOCAL_MODULE_TAGS := debug
include $(DLKM_DIR)/AndroidKernelModule.mk
endif
@@ -0,0 +1,3 @@
# Kernel module make instructions go here.
#
obj-m := bus_timeout_mod.o
@@ -0,0 +1,23 @@
#
# Rules for building kernel-tests should go in this file.
#
bus_timeoutdir = $(prefix)
# See the automake manual for full details of this syntax.
bus_timeout_PROGRAMS = bus_timeout_mod
# Uncomment this if your script needs to install the 'common' setup
# script from android.
dist_bus_timeout_SCRIPTS += ../test_env_setup.sh
#-----------------------------------------------------------------------------
# Below this line is automake boilerplate. Casual users should not need
# to go below this line.
PWD := $(shell pwd)
all-local:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
install-exec-local:
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(DESTDIR)$(prefix) modules_install
depmod $(shell cat $(KERNELDIR)/include/config/kernel.release 2> /dev/null) -b $(DESTDIR)$(prefix)
@@ -0,0 +1,20 @@
Bus Timeout Documentation
Usage: insert module
OPTIONS: (none)
TEST BEHAVIOR: Force a bus hang. If successful, the target will be reset by
the watchdog. The kernel will panic on a failure. Returning back to the command
prompt is also considered a failure.
LIMITATIONS: In order for the test to run correctly, clocks must be off.
Unfortunately, there is no guarantee with the public clock APIs that the
clock will actually be off after one clk_disable call. The easiest way
to guarantee that the disable will actually work is to make sure the
system is not using the required clocks.
For this module, the camera must not be on while attempting to do the
test since the camera registers are used for testing.
TARGETS: 8974
@@ -0,0 +1,337 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. 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 and
* only 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.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#define AHB_BUS_TIMEOUT 0xFD4A0800
#define SEC_WDOG 0xFC4AA000
#define WDT0_RST 0x04
#define WDT0_EN 0x08
struct clk_pair {
const char *dev;
const char *clk;
};
static int bus_timeout_camera;
static int bus_timeout_usb;
static int pc_save;
static int bus_timeout_camera_set(const char *val, struct kernel_param *kp);
module_param_call(bus_timeout_camera, bus_timeout_camera_set, param_get_int,
&bus_timeout_camera, 0644);
static int bus_timeout_usb_set(const char *val, struct kernel_param *kp);
module_param_call(bus_timeout_usb, bus_timeout_usb_set, param_get_int,
&bus_timeout_usb, 0644);
static int pc_save_set(const char *val, struct kernel_param *kp);
module_param_call(pc_save, pc_save_set, param_get_int, &pc_save, 0644);
static struct clk_pair bus_timeout_camera_clocks_on[] = {
/*
* gcc_mmss_noc_cfg_ahb_clk should be on but right
* now this clock is on by default and not accessable.
* Update this table if gcc_mmss_noc_cfg_ahb_clk is
* ever not enabled by default!
*/
{
.dev = "fda0c000.qcom,cci",
.clk = "camss_top_ahb_clk",
},
{
.dev = "fda10000.qcom,vfe",
.clk = "iface_clk",
},
};
static struct clk_pair bus_timeout_camera_clocks_off[] = {
{
.dev = "fda10000.qcom,vfe",
.clk = "camss_vfe_vfe_clk",
}
};
static struct clk_pair bus_timeout_usb_clocks_on[] = {
{
.dev = "f9a55000.usb",
.clk = "iface_clk",
},
{
.dev = "f9a55000.usb",
.clk = "core_clk",
},
{
.dev = "msm_otg",
.clk = "iface_clk",
},
{
.dev = "msm_otg",
.clk = "core_clk",
},
};
static struct clk_pair bus_timeout_usb_clocks_off[] = {
{
.dev = "f9a55000.usb",
.clk = "core_clk",
},
{
.dev = "msm_otg",
.clk = "core_clk",
},
};
static void bus_timeout_clk_access(struct clk_pair bus_timeout_clocks_off[],
struct clk_pair bus_timeout_clocks_on[],
int off_size, int on_size)
{
int i;
/*
* Yes, none of this cleans up properly but the goal here
* is to trigger a hang which is going to kill the rest of
* the system anyway
*/
for (i = 0; i < on_size; i++) {
struct clk *this_clock;
this_clock = clk_get_sys(bus_timeout_clocks_on[i].dev,
bus_timeout_clocks_on[i].clk);
if (!IS_ERR(this_clock))
if (clk_prepare_enable(this_clock))
pr_warn("Device %s: Clock %s not enabled",
bus_timeout_clocks_on[i].clk,
bus_timeout_clocks_on[i].dev);
}
for (i = 0; i < off_size; i++) {
struct clk *this_clock;
this_clock = clk_get_sys(bus_timeout_clocks_off[i].dev,
bus_timeout_clocks_off[i].clk);
if (!IS_ERR(this_clock))
clk_disable_unprepare(this_clock);
}
}
static int bus_timeout_camera_set(const char *val, struct kernel_param *kp)
{
int ret;
uint32_t dummy;
uint32_t address = 0xfda10000;
void *hang_addr;
struct regulator *r;
ret = param_set_int(val, kp);
if (ret)
return ret;
if (bus_timeout_camera != 1)
return -EPERM;
hang_addr = ioremap(address, SZ_4K);
r = regulator_get(NULL, "gdsc_vfe");
ret = IS_ERR(r);
if (!ret)
regulator_enable(r);
else {
pr_err("Bus timeout test: Unable to get regulator reference\n");
return ret;
}
bus_timeout_clk_access(bus_timeout_camera_clocks_off,
bus_timeout_camera_clocks_on,
ARRAY_SIZE(bus_timeout_camera_clocks_off),
ARRAY_SIZE(bus_timeout_camera_clocks_on));
dummy = readl_relaxed(hang_addr);
mdelay(15000);
pr_err("Bus timeout test failed\n");
iounmap(hang_addr);
return -EIO;
}
static int bus_timeout_usb_set(const char *val, struct kernel_param *kp)
{
int ret;
uint32_t dummy;
uint32_t address = 0xf9a55000;
void *hang_addr;
ret = param_set_int(val, kp);
if (ret)
return ret;
if (bus_timeout_usb != 1)
return -EPERM;
hang_addr = ioremap(address, SZ_4K);
bus_timeout_clk_access(bus_timeout_usb_clocks_off,
bus_timeout_usb_clocks_on,
ARRAY_SIZE(bus_timeout_usb_clocks_off),
ARRAY_SIZE(bus_timeout_usb_clocks_on));
dummy = readl_relaxed(hang_addr);
mdelay(15000);
pr_err("Bus timeout test failed: 0x%x\n", dummy);
iounmap(hang_addr);
return -EIO;
}
static const struct of_device_id apps_wdog_of_match[] = {
{ .compatible = "qcom,msm-watchdog" },
{},
};
static void __iomem *wdogbase;
static int msm_apps_wdog_probe(void)
{
int ret;
struct device_node *node;
uint32_t base;
node = of_find_matching_node(NULL, apps_wdog_of_match);
if (node) {
ret = of_property_read_u32(node, "reg", &base);
if (ret) {
pr_err("PC-Save test: Cannot read wdog base\n");
return ret;
}
wdogbase = ioremap(base, SZ_4K);
if (!wdogbase) {
pr_err("PC-save test: Cannot map wdog register space\n");
return -ENOMEM;
}
} else {
pr_info("PC-save test: wdog node not found\n");
return -EINVAL;
}
return 0;
}
static void msm_apps_wdog_disable(void)
{
__raw_writel(1, wdogbase + WDT0_RST);
__raw_writel(0, wdogbase + WDT0_EN);
mb();
}
static int pc_save_set(const char *val, struct kernel_param *kp)
{
int ret;
uint32_t dummy;
uint32_t address = 0xfda10000;
void *hang_addr;
void *global_bus_timeout_disable;
struct regulator *r;
void *sec_wdog_virt;
uint32_t sec_status;
ret = param_set_int(val, kp);
if (ret)
return ret;
if (pc_save != 1)
return -EPERM;
ret = msm_apps_wdog_probe();
if (ret)
return ret;
hang_addr = ioremap(address, SZ_4K);
if (!hang_addr) {
pr_err("PC-save test: unable to map hang address\n");
return -ENOMEM;
}
global_bus_timeout_disable = ioremap(AHB_BUS_TIMEOUT, SZ_4K);
if (!global_bus_timeout_disable) {
pr_err("PC-save test: unable to map bus timeout disable\
AHB_BUS_TIMEOUT register\n");
iounmap(hang_addr);
iounmap(wdogbase);
return -ENOMEM;
}
r = regulator_get(NULL, "gdsc_vfe");
ret = IS_ERR(r);
if (!ret) {
ret = regulator_enable(r);
if (ret < 0) {
pr_err("PC-save test: unable to enable regulator\n");
return ret;
}
} else {
pr_err("PC-save test: Unable to get regulator reference\n");
return ret;
}
bus_timeout_clk_access(bus_timeout_camera_clocks_off,
bus_timeout_camera_clocks_on,
ARRAY_SIZE(bus_timeout_camera_clocks_off),
ARRAY_SIZE(bus_timeout_camera_clocks_on));
sec_wdog_virt = ioremap(SEC_WDOG, SZ_4K);
if (!sec_wdog_virt) {
pr_err("unable to map sec wdog page\n");
iounmap(hang_addr);
iounmap(wdogbase);
iounmap(global_bus_timeout_disable);
return -ENOMEM;
}
/* Disable sec watchdog */
writel_relaxed(0x1, sec_wdog_virt);
sec_status = readl_relaxed(sec_wdog_virt + 0x04);
writel_relaxed(sec_status & ~0x1, (sec_wdog_virt + 0x04));
/* Make sure sec watchdog is disabled before continuing */
mb();
/* Disable apps watchdog */
msm_apps_wdog_disable();
/* Set sec watchdog bite time < bark time */
writel_relaxed(0x7FFFF, (sec_wdog_virt + 0x0C));
/* 1ms bite time in sleep clock cycles */
writel_relaxed(0x20, (sec_wdog_virt + 0x10));
writel_relaxed(sec_status | 0x1, (sec_wdog_virt + 0x04));
/* Make sure sec watchdog is enabled before continuing */
mb();
/* Disable Bus timeout */
writel_relaxed(0x0, global_bus_timeout_disable);
/* Make sure bus timeout is disabled before continuing */
mb();
dummy = readl_relaxed(hang_addr);
mdelay(15000);
pr_err("Bus timeout test failed\n");
iounmap(hang_addr);
iounmap(wdogbase);
iounmap(global_bus_timeout_disable);
iounmap(sec_wdog_virt);
return -EIO;
}
static int bus_timeout_init(void)
{
return 0;
}
static void bus_timeout_exit(void)
{
}
module_init(bus_timeout_init);
module_exit(bus_timeout_exit);
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,96 @@
AC_PREREQ(2.64)
AC_INIT([kernel-tests],[1.0.0])
AM_INIT_AUTOMAKE([-Wall -Werror gnu foreign])
AM_MAINTAINER_MODE
AC_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
# Checks for programs.
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_LIBTOOL
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_ARG_WITH(sanitized-headers,
AS_HELP_STRING([--with-sanitized-headers=DIR],
[Specify the location of the sanitized Linux headers]),
[CPPFLAGS="$CPPFLAGS -I$withval"])
AC_ARG_ENABLE(big-tests,
AS_HELP_STRING([--enable-big-tests],
[Include tests that use a lot of disk [default=yes]]),
[case "${enableval}" in
yes) BIGTESTS=true ;;
no) BIGTESTS=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-big-tests]) ;;
esac],
[BIGTESTS=true])
AM_CONDITIONAL(BIGTESTS, [test x$BIGTESTS = xtrue])
AC_ARG_WITH([kernel],
AS_HELP_STRING([--with-kernel=DIR],
[location of a built kernel; used for building kernel modules]),
[case "${with_kernel}" in
yes|'') AC_MSG_ERROR([--with-kernel must specify a path]) ;;
no) with_kernel= ;;
*)
if [test ! -f ${with_kernel}/Makefile]; then
AC_MSG_ERROR([bad value '${with_kernel}' for --with-kernel; cannot find '${with_kernel}/Makefile'])
fi ;;
esac])
if [test -z "${with_kernel}"]; then
AC_MSG_WARN([no kernel specified; kernel modules will not be included])
else
AC_SUBST([KERNEL_DIR], [${with_kernel}])
fi
AM_CONDITIONAL(KERNELMODULES, [test -n "${with_kernel}"])
#
# Build all kernel tests by default
#
# To add new tests add ENABLE_KERNEL_TEST and update AC_CONFIG_FILES
#
# Tests which will be too large to fit in an initrd/initramfs should not
# be installed if the conditional BIGTESTS is false.
#
# ion
ENABLE_KERNEL_TEST([ion],[include the ion test (default=yes)])
# memory_prof
ENABLE_KERNEL_TEST([memory_prof],[include the memory profiling test (default=yes)])
# msm-bus
ENABLE_KERNEL_TEST([msm-bus],[include the MSM bus test (default=yes)])
# sps
ENABLE_KERNEL_TEST([sps],[include the sps test (default=yes)])
# v4l2apps
ENABLE_KERNEL_TEST([v4l2apps],[include the v4l2apps test (default=no)],[no])
# watchdog
ENABLE_KERNEL_TEST([watchdog],[include the watchdog test (default=yes)])
# ocmem
ENABLE_KERNEL_TEST([ocmem],[include the ocmem test (default=yes)])
AC_SUBST([CFLAGS])
AC_SUBST([CC])
AC_CONFIG_FILES([
Makefile
ion/Makefile
memory_prof/Makefile
msm_bus/Makefile
ocmem/Makefile
sps/Makefile
v4l2apps/Makefile
watchdog/Makefile
])
AC_OUTPUT
@@ -0,0 +1,26 @@
BOARD_PLATFORM_LIST := msm8974
BOARD_PLATFORM_LIST += msm8226
BOARD_PLATFORM_LIST += msm8610
ifeq ($(call is-board-platform-in-list,$(BOARD_PLATFORM_LIST)),true)
LOCAL_PATH := $(call my-dir)
define ADD_TEST
include $(CLEAR_VARS)
LOCAL_MODULE := $1
LOCAL_SRC_FILES := $1
LOCAL_MODULE_CLASS := EXECUTABLE
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests/coresight/core
include $(BUILD_PREBUILT)
endef
TEST_LIST := cs_adversary.sh cs_common.sh cs_test.sh run.sh README.txt
$(foreach TEST,$(TEST_LIST),$(eval $(call ADD_TEST,$(TEST))))
include $(LOCAL_PATH)/*/Android.mk
endif
@@ -0,0 +1,88 @@
Test: coresight
Usage: cs_test.sh [-n | --nominal] [-a | --adversarial] [-r | --repeatability]\
[-s | stress ]
Runs the tests for CoreSight trace drivers.
Options:
The following options can be used:
-n | --nominal nominal test, runs by default
-a | --adversarial adversarial test
-r | --repeatability iterations repeatability test, runs 10
iterations by default
-s | --stress stress test
--source trace_source trace source, supported
trace_source values are 'etm'
and 'stm'
Requirement:
CoreSight ETM and STM sources are initially disabled before running any test.
Description:
Nominal Test:
All CoreSight tests are invoked.
Adversarial Test:
Runs cs_adversary.sh. This test enables all trace sources, all ftrace events and
toggles the cpu cores on/off.
Repeatability Tests:
All test cases except probe test are invoked for user specified number of iterations,
or for 10 iterations by default.
Stress Test:
All test cases except probe test are invoked for 100 iterations.
Test case description:
1. platform/platform.sh
Tests that CoreSight trace drivers are probed without failures.
2. etm/etm_enable.sh
Tests ETM tracing gets properly enabled.
3. etm/etm_disable.sh
Tests ETM tracing get properly disabled.
4. stm/stm_enable.sh
Tests STM tracing gets properly enabled.
5. stm/stm_disable.sh
Tests STM tracing gets properly disabled.
6. stm/stm_etf_dump.sh
Tests ETF can be dumped with good data while STM is the only trace source. All ftrace,
hardware events are disabled while single string data is sent over STM. Once trailing
zeros of output file are truncated, size is compared with reference size for same
input data.
7. stm/stm_etr_dump.sh
Please refer to stm/stm_etf_dump.sh. Here ETR is the trace sink instead of ETM.
8. mult_trace/mult_source_enable.sh
Tests that multiple CoreSight trace sources (ETM and STM) can be successfully enabled
at the same time.
9. mult_trace/mult_source_disable.sh
Tests that multiple CoreSight trace sources (ETM and STM) can be successfully disabled
at the same time.
10. sink_switch/sinkswitch.sh
Tests that the device can switch between multiple CoreSight tracesinks. Assumes etf,
etr and tpiu sinks are present.
11. sink_switch/etr_modes.sh
Tests that the modes of ETR can be changed from usb to memory and vice versa.
12. cs_adversary.sh
While having trace sources enabled, enables and disables all cores in a loop.
Targets supported: 8974
Test output:
All tests prints:
"PASS: <message>" if the test case passes
or
"FAIL: <message>" otherwise
Note: Tests assume /data partition exists
@@ -0,0 +1,87 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
online_offline_cores() {
cores=`grep -c "processor" $cpuinfo`
count=1
loop=10
stop mpdecision
#off-on each core in sequence. Repeat 10 times
for i in $(seq 1 $loop)
do
while [ $count -lt $cores ]
do
echo 0 > $cpupath$count"/online"
sleep 1
echo 1 > $cpupath$count"/online"
count=$(( count + 1 ))
done
done
#off-on multiple cores at a time. Repeat 10 times
loop=10
count=1
for i in $(seq 1 $loop)
do
while [ $count -lt $cores ]
do
echo 0 > $cpupath$count"/online"
count=$(( count + 1 ))
done
sleep 1
count=1
while [ $count -lt $cores ]
do
echo 1 > $cpupath$count"/online"
count=$(( count + 1 ))
done
done
start mpdecision
}
echo "-----Coresight Trace Driver Adversarial Test Starting-----"
echo "----------------------------------------------------------"
source "$(dirname $0)/cs_common.sh"
etm_enable_all_cores
stm_enable
if [ ! -d $debugfs ]
then
mkdir -p $debugfs
fi
mount -t debugfs nodev $debugfs 2>"/dev/null"
echo 1 > $debugfs"/tracing/tracing_on"
echo 1 > $debugfs"/tracing/events/enable"
echo "*:*" > $debugfs"/tracing/set_event"
online_offline_cores
etm_disable_all_cores
stm_disable
umount $debugfs 2>"/dev/null"
echo "PASS: Online-Offline all cores with trace drivers enabled"
echo "-----Coresight Trace Driver Adversarial Test Complete-----"
echo "----------------------------------------------------------"
echo ""
+236
View File
@@ -0,0 +1,236 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cpupath="/sys/devices/system/cpu/cpu"
cpuinfo="/proc/cpuinfo"
csrpath="/sys/bus/coresight/devices/coresight-csr"
debugfs="/sys/kernel/debug"
etmpath="/sys/bus/coresight/devices/coresight-etm"
f0path="/sys/bus/coresight/devices/coresight-funnel-in0"
f1path="/sys/bus/coresight/devices/coresight-funnel-in1"
fmergpath="/sys/bus/coresight/devices/coresight-funnel-merg"
fkpsspath="/sys/bus/coresight/devices/coresight-funnel-kpss"
fmmsspath="/sys/bus/coresight/devices/coresight-funnel-mmss"
replicatorpath="/sys/bus/coresight/devices/coresight-replicator"
stmpath="/sys/bus/coresight/devices/coresight-stm"
tmcetfpath="/sys/bus/coresight/devices/coresight-tmc-etf"
tmcetrpath="/sys/bus/coresight/devices/coresight-tmc-etr"
tpiupath="/sys/bus/coresight/devices/coresight-tpiu"
#===============================================================
#function to enable etm for all cores
#returns 0 if etm for all cores are present and could be written to, 1 otherwise
#===============================================================
etm_enable_all_cores() {
count=0
retval=0
cores=`grep -c "processor" $cpuinfo`
stop mpdecision
while [ $count -lt $cores ]
do
etmpath_enable=$etmpath$count"/enable"
cpupath_enable=$cpupath$count"/online"
echo 1 > $cpupath_enable
if [ -f $etmpath_enable ]
then
echo 1 > $etmpath_enable
else
echo "FAIL: No coresight-etm$count driver present ****"
retval=1
fi
count=$(( count + 1 ))
done
start mpdecision
return $retval
}
#=============================================================
#function to test if etm of all cores are enabled
#returns 0 if all cores are enabled, 1 otherwise
#=============================================================
etm_test_if_enabled() {
count=0
retval=0
cores=`grep -c "processor" $cpuinfo`
while [ $count -lt $cores ]
do
etmpath_enable=$etmpath$count"/enable"
if [ -f $etmpath_enable ]
then
read value < $etmpath_enable
if [ $value != "1" ]
then
echo "FAIL: coresight-etm$count device not enabled ****"
retval=1
fi
else
retval=1
fi
count=$(( count + 1 ))
done
return $retval
}
#===============================================================
#function to disable etm for all cores
#returns 0 if etm for all cores are present and could be written to, 1 otherwise
#===============================================================
etm_disable_all_cores() {
count=0
retval=0
cores=`grep -c "processor" $cpuinfo`
stop mpdecision
while [ $count -lt $cores ]
do
etmpath_enable=$etmpath$count"/enable"
cpupath_enable=$cpupath$count"/online"
echo 1 > $cpupath_enable
if [ -f $etmpath_enable ]
then
echo 0 > $etmpath_enable
else
echo "FAIL: No coresight-etm$count driver present ****"
retval=1
fi
count=$(( count + 1 ))
done
start mpdecision
return $retval
}
#=============================================================
#function to test if etm of all cores are disabled
#returns 0 if all cores are disabled, 1 otherwise
#=============================================================
etm_test_if_disabled() {
count=0
retval=0
cores=`grep -c "processor" $cpuinfo`
while [ $count -lt $cores ]
do
etmpath_enable=$etmpath$count"/enable"
if [ -f $etmpath_enable ]
then
read value < $etmpath_enable
if [ $value != "0" ]
then
echo "FAIL: coresight-etm$count device not disabled ****"
retval=1
fi
else
retval=1
fi
count=$(( count + 1 ))
done
return $retval
}
#==============================================================
#function to enable stm
#returns 0 if device is written to, 1 otherwise
#==============================================================
stm_enable() {
stmpath_enable=$stmpath"/enable"
if [ -f $stmpath_enable ]
then
echo 1 > $stmpath_enable
retval=0
else
echo "FAIL: No coresight-stm driver present ****"
retval=1
fi
return $retval
}
#==============================================================
#function to test if stm is enabled
#returns 0 on success, 1 otherwise
#==============================================================
stm_test_if_enabled() {
stmpath_enable=$stmpath"/enable"
if [ -f $stmpath_enable ]
then
read value < $stmpath_enable
if [ $value = "1" ]
then
retval=0
else
echo "FAIL: coresight-stm device not enabled ****"
retval=1
fi
else
retval=1
fi
return $retval
}
#==============================================================
#function to disable stm
#returns 0 if device could be written to, 1 otherwise
#==============================================================
stm_disable() {
stmpath_enable=$stmpath"/enable"
if [ -f $stmpath_enable ]
then
echo 0 > $stmpath_enable
retval=0
else
echo "FAIL: No coresight-stm driver present ****"
retval=1
fi
return $retval
}
#===============================================================
#function to test if stm is disabled
#returns 0 on success, 1 otherwise
#===============================================================
stm_test_if_disabled() {
stmpath_enable=$stmpath"/enable"
if [ -f $stmpath_enable ]
then
read value < $stmpath_enable
if [ $value = "0" ]
then
retval=0
else
echo "FAIL: coresight-stm device not disabled ****"
retval=1
fi
else
retval=1
fi
return $retval
}
+242
View File
@@ -0,0 +1,242 @@
#! /bin/sh --
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Invoked by run.sh
directory=$(cd `dirname $0` && pwd)
#Requirement: Before running test, ensure STM/ETM is initially disabled
cs_test_setup(){
source "$(dirname $0)/cs_common.sh"
retval=0
if [ $stm -eq 1 ]
then
stm_disable
retval=$?
fi
if [ $retval -eq 0 ] && [ $etm -eq 1 ]
then
etm_disable_all_cores
retval=$?
fi
if [ $retval -ne 0 ]
then
echo "Requirement for running test:"
echo "ETM/STM cannot be disabled. Exiting tests"
exit 1
fi
}
cs_nominal(){
cd $directory"/platform" && sh platform.sh
if [ $etm -eq 1 ]
then
cd $directory"/etm" && sh etm_enable.sh
cd $directory"/etm" && sh etm_disable.sh
fi
if [ $stm -eq 1 ]
then
cd $directory"/stm" && sh stm_enable.sh
cd $directory"/stm" && sh stm_disable.sh
cd $directory"/stm" && sh stm_etf_dump.sh
cd $directory"/stm" && sh stm_etr_dump.sh
fi
if [ $stm -eq 1 ] && [ $etm -eq 1 ]
then
cd $directory"/mult_trace" && sh mult_source_enable.sh
cd $directory"/mult_trace" && sh mult_source_disable.sh
fi
cd $directory"/sink_switch" && sh sinkswitch.sh "--source $source"
cd $directory"/sink_switch" && sh etr_modes.sh "--source $source"
}
cs_adversary(){
if [ $stm -eq 1 ] && [ $etm -eq 1 ]
then
cd $directory && sh cs_adversary.sh
else
echo "Both STM and ETM required as trace source."
fi
}
cs_repeatability(){
if [ $# -eq 1 ]
then
run=$1
else
run=10
fi
if [ $etm -eq 1 ]
then
echo "Coresight ETM enable/disable repeat test started for $run
iterations"
for i in $(seq 1 $run)
do
cd $directory"/etm" && sh etm_enable.sh
cd $directory"/etm" && sh etm_disable.sh
done
fi
if [ $stm -eq 1 ]
then
echo "Coresight STM enable/disable repeat test started for $run
iterations"
for i in $(seq 1 $run)
do
cd $directory"/stm" && sh stm_enable.sh
cd $directory"/stm" && sh stm_disable.sh
done
echo "Coresight STM ETF dump test started for $run iterations"
for i in $(seq 1 $run)
do
cd $directory"/stm" && sh stm_etf_dump.sh
done
echo "Coresight STM ETR dump test started for $run iterations"
for i in $(seq 1 $run)
do
cd $directory"/stm" && sh stm_etr_dump.sh
done
fi
if [ $stm -eq 1 ] && [ $etm -eq 1 ]
then
echo "Coresight multi trace enable/disable repeat test started for
$run iterations"
for i in $(seq 1 $run)
do
cd $directory"/mult_trace" && sh mult_source_enable.sh
cd $directory"/mult_trace" && sh mult_source_disable.sh
done
fi
echo "Coresight sink switching repeat test started for $run iterations"
for i in $(seq 1 $run)
do
cd $directory"/sink_switch" && sh sinkswitch.sh "--source $source"
done
echo "Coresight ETR modes change started for $run iterations"
for i in $(seq 1 $run)
do
cd $directory"/sink_switch" && sh etr_modes.sh "--source $source"
done
if [ $stm -eq 1 ] && [ $etm -eq 1 ]
then
echo "CoreSight adversarial repeat test started for $run iterations"
for i in $(seq 1 $run)
do
cd $directory && sh cs_adversary.sh
done
fi
}
cs_stress(){
run=100
echo "Coresight stress test started"
for i in $(seq 1 $run)
do
cs_adversary
done
}
source=`echo "$*" | sed -n 's/.*--source \(\w*\).*/\1/p'`
source=`echo $source | tr '[A-Z]' '[a-z]'`
if [[ "$source" ]]
then
if [[ $source == "stm" ]]
then
echo "All STM tests will be run"
stm=1
etm=0
elif [[ $source == "etm" ]]
then
echo "All ETM tests will be run"
stm=0
etm=1
fi
else
stm=1
etm=1
fi
if [[ $# -le 2 && -n "$source" || $# -eq 0 ]]
then
cs_test_setup
cs_nominal
exit 0
else
while [ $# -gt 0 ]
do
case $1 in
-n | --nominal)
echo "Coresight nominal test started"
cs_test_setup
cs_nominal
shift 1
;;
-a | --adversarial)
echo "Coresight adversarial test started"
cs_test_setup
cs_adversary
shift 1
;;
-r | --repeatability)
echo "Coresight repeatability test started"
shift 1
if [ "$1" -gt 0 ]
then
cs_test_setup
cs_repeatability $1
shift 1
else
echo "Invalid number of iterations, doing 10 iterations by default"
cs_test_setup
cs_repeatability 10
fi
;;
-s | --stress)
echo "Coresight stress test started"
cs_test_setup
cs_repeatability 100
shift 1
;;
--source)
shift 1
shift 1
;;
-h | --help | *)
echo "Usage: $0 [-n | --nominal] [-a | --adversarial ] \\ "
echo " [-r | --repeatability] [iterations] [-s | --stress ] \\"
echo " [--source] [trace_source]"
echo "Runs the coresight driver tests. If no options are provided "
echo "then nominal tests are run. If no iterations are provided for "
echo "repeatability tests, 10 is the default iteration. By default "
echo "both ETM and STM are enabled"
exit 1
;;
esac
done
exit 0
fi
@@ -0,0 +1,16 @@
LOCAL_PATH := $(call my-dir)
define ADD_TEST
include $(CLEAR_VARS)
LOCAL_MODULE := $1
LOCAL_SRC_FILES := $1
LOCAL_MODULE_CLASS := EXECUTABLE
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests/coresight/core/etm
include $(BUILD_PREBUILT)
endef
TEST_LIST := etm_enable.sh etm_disable.sh
$(foreach TEST,$(TEST_LIST),$(eval $(call ADD_TEST,$(TEST))))
@@ -0,0 +1,42 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
echo "-----Coresight ETM Disable Test(allcores) Starting-----"
echo "------------------------------------------------------"
source "$(dirname $0)/../cs_common.sh"
etm_disable_all_cores
etm_test_if_disabled
retval=$?
if [ $retval -eq 0 ]
then
echo "PASS: All ETM devices disabled"
fi
echo "-----Coresight ETM Disable Test(allcores) Complete-----"
echo "------------------------------------------------------"
echo ""
@@ -0,0 +1,42 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
echo "-----Coresight ETM Enable Test(allcores) Starting-----"
echo "------------------------------------------------------"
source "$(dirname $0)/../cs_common.sh"
etm_enable_all_cores
etm_test_if_enabled
retval=$?
if [ $retval -eq 0 ]
then
echo "PASS: All ETM devices enabled"
fi
echo "-----Coresight ETM Enable Test(allcores) Complete-----"
echo "------------------------------------------------------"
echo ""
@@ -0,0 +1,16 @@
LOCAL_PATH := $(call my-dir)
define ADD_TEST
include $(CLEAR_VARS)
LOCAL_MODULE := $1
LOCAL_SRC_FILES := $1
LOCAL_MODULE_CLASS := EXECUTABLE
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests/coresight/core/mult_trace
include $(BUILD_PREBUILT)
endef
TEST_LIST := mult_source_disable.sh mult_source_enable.sh
$(foreach TEST,$(TEST_LIST),$(eval $(call ADD_TEST,$(TEST))))
@@ -0,0 +1,65 @@
#! /bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
echo "-----Coresight Multiple Test Source Disable Test Starting-----"
echo "-------------------------------------------------------------"
source "$(dirname $0)/../cs_common.sh"
etm_disable_all_cores
retval=$?
if [ $retval -eq 1 ]
then
echo "NA: ETM not present for all cores"
else
stm_disable
retval=$?
if [ $retval -eq 1 ]
then
echo "NA: STM not present"
else
etm_test_if_disabled
retval=$?
if [ $retval -eq 1 ]
then
echo "FAIL: ETM is not disabled"
else
stm_test_if_disabled
retval=$?
if [ $retval -eq 1 ]
then
echo "FAIL: STM is not disabled"
else
echo "PASS: both ETM and STM are disabled"
fi
fi
fi
fi
echo "-----Coresight Multiple Test Source Disable Test Complete-----"
echo "--------------------------------------------------------------"
echo ""
@@ -0,0 +1,65 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
echo "-----Coresight Multiple Test Source Enable Test Starting-----"
echo "-------------------------------------------------------------"
source "$(dirname $0)/../cs_common.sh"
etm_enable_all_cores
retval=$?
if [ $retval -eq 1 ]
then
echo "NA: ETM not present for all cores"
else
stm_enable
retval=$?
if [ $retval -eq 1 ]
then
echo "NA: STM not present"
else
etm_test_if_enabled
retval=$?
if [ $retval -eq 1 ]
then
echo "FAIL: ETM is not enabled"
else
stm_test_if_enabled
retval=$?
if [ $retval -eq 1 ]
then
echo "FAIL: STM is not enabled"
else
echo "PASS: both ETM and STM are enabled"
fi
fi
fi
fi
echo "-----Coresight Multiple Test Source Enable Test Complete-----"
echo "-------------------------------------------------------------"
echo ""
@@ -0,0 +1,9 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := platform.sh
LOCAL_SRC_FILES := platform.sh
LOCAL_MODULE_CLASS := EXECUTABLE
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests/coresight/core/platform
include $(BUILD_PREBUILT)
@@ -0,0 +1,107 @@
#! /bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
count=0
source "$(dirname $0)/../cs_common.sh"
echo "-----Coresight Platform Test Starting-----"
echo "------------------------------------------"
if [ -d $csrpath ]
then
echo "PASS: coresight-csr driver initialized"
else
echo "FAIL: coresight-csr driver probe failed ****"
fi
cores=`grep -c "processor" $cpuinfo`
while [ $count -lt $cores ]
do
if [ -d $etmpath$count ]
then
echo "PASS: coresight-etm$count driver initialized"
else
echo "FAIL: coresight-etm$count driver probe failed ****"
fi
count=$(( count + 1 ))
done
if [ -d $f0path ]
then
echo "PASS: coresight-funnel-in0 driver initialized"
else
echo "FAIL: coresight-funnel-in0 driver probe failed ****"
fi
if [ -d $f1path ]
then
echo "PASS: coresight-funnel-in1 driver initialized"
else
echo "FAIL: coresight-funnel-in1 driver probe failed ****"
fi
if [ -d $fmergpath ]
then
echo "PASS: coresight-funnel-merg driver initialized"
else
echo "FAIL: coresight-funnel-merg driver probe failed ****"
fi
if [ -d $fkpsspath ]
then
echo "PASS: coresight-funnel-kpss driver initialized"
else
echo "FAIL: coresight-funnel-kpss driver probe failed ****"
fi
if [ -d $fmmsspath ]
then
echo "PASS: coresight-funnel-mmss driver initialized"
else
echo "FAIL: coresight-funnel-mmss driver probe failed ****"
fi
if [ -d $replicatorpath ]
then
echo "PASS: coresight-replicator driver initialized"
else
echo "FAIL: coresight-replicator driver probe failed ****"
fi
if [ -d $stmpath ]
then
echo "PASS: coresight-stm driver initialized"
else
echo "FAIL: coresight-stm driver probe failed ****"
fi
if [ -d $tmcetfpath ] && [ -d $tmcetrpath ]
then
echo "PASS: coresight-tmc driver initialized"
else
echo "FAIL: coresight-tmc driver probe failed ****"
fi
if [ -d $tpiupath ]
then
echo "PASS: coresight-tpu driver initialized"
else
echo "FAIL: coresight-tpu driver probe failed ****"
fi
echo "-----Coresight Platform Test Complete-----"
echo "------------------------------------------"
echo ""
+32
View File
@@ -0,0 +1,32 @@
#! /bin/sh --
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
cd `dirname $0` && exec ./cs_test.sh $@
@@ -0,0 +1,16 @@
LOCAL_PATH := $(call my-dir)
define ADD_TEST
include $(CLEAR_VARS)
LOCAL_MODULE := $1
LOCAL_SRC_FILES := $1
LOCAL_MODULE_CLASS := EXECUTABLE
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests/coresight/core/sink_switch
include $(BUILD_PREBUILT)
endef
TEST_LIST := etr_modes.sh sinkswitch.sh
$(foreach TEST,$(TEST_LIST),$(eval $(call ADD_TEST,$(TEST))))
@@ -0,0 +1,77 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
echo "-----Coresight ETR Switch Modes Test-----"
echo "-----------------------------------------"
source=`echo "$*" | sed -n 's/.*--source \(\w*\).*/\1/p'`
source=`echo $source | tr '[A-Z]' '[a-z]'`
#enable ETM and STM source
source "$(dirname $0)/../cs_common.sh"
if [[ -z "$source" ]]
then
source="all"
fi
if [[ $source != "stm" ]]
then
etm_enable_all_cores
fi
if [[ $source != "etm" ]]
then
stm_enable
fi
etrmode=$tmcetrpath"/out_mode"
#set etr mode to memory before starting test
echo "mem" > $etrmode
#change mode to usb
echo "usb" > $etrmode
value=`cat $etrmode`
if [[ $value != "usb" ]]
then
echo "FAIL: Changing ETR mode from memory to usb failed ****"
else
echo "mem" > $etrmode
value=`cat $etrmode`
if [[ $value != "mem" ]]
then
echo "FAIL: Changing ETR mode from usb to memory failed ****"
else
echo "PASS: Changed ETR modes successfully"
fi
fi
if [[ $source != "stm" ]]
then
etm_disable_all_cores
fi
if [[ $source != "etm" ]]
then
stm_disable
fi
echo "----- Coresight ETR Switch Modes Test Complete-----"
echo "---------------------------------------------------"
echo ""
@@ -0,0 +1,111 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
etfsink="/sys/bus/coresight/devices/coresight-tmc-etf/curr_sink"
etrsink="/sys/bus/coresight/devices/coresight-tmc-etr/curr_sink"
tpiusink="/sys/bus/coresight/devices/coresight-tpiu/curr_sink"
echo "-----Coresight Sink Switching Test-----"
echo "---------------------------------------"
source=`echo "$*" | sed -n 's/.*--source \(\w*\).*/\1/p'`
source=`echo $source | tr '[A-Z]' '[a-z]'`
#enable ETM and STM source
source "$(dirname $0)/../cs_common.sh"
if [[ -z "$source" ]]
then
source="all"
fi
if [[ $source != "stm" ]]
then
etm_enable_all_cores
fi
if [[ $source != "etm" ]]
then
stm_enable
fi
echo 1 > $etrsink
read etfstatus < $etfsink
read etrstatus < $etrsink
read tpiustatus < $tpiusink
if [ $etfstatus = 0 ] && [ $etrstatus = 1 ] && [ $tpiustatus = 0 ]
then
echo "PASS: Changed current sink to ETR"
else
echo "FAIL: Sink Switching to ETR failed ****"
fi
echo 1 > $tpiusink
read etfstatus < $etfsink
read etrstatus < $etrsink
read tpiustatus < $tpiusink
if [ $etfstatus = 0 ] && [ $etrstatus = 0 ] && [ $tpiustatus = 1 ]
then
echo "PASS: Changed current sink to TPIU"
else
echo "FAIL: Sink Switching to TPIU failed ****"
fi
echo 1 > $etfsink
read etfstatus < $etfsink
read etrstatus < $etrsink
read tpiustatus < $tpiusink
if [ $etfstatus = 1 ] && [ $etrstatus = 0 ] && [ $tpiustatus = 0 ]
then
echo "PASS: Changed current sink to ETF"
else
echo "FAIL: Sink Switching to ETF failed ****"
fi
#test if trace sources are still enabled
if [[ $source != "stm" ]]
then
etm_test_if_enabled
retval=$?
if [ $retval -eq 0 ]
then
echo "PASS: All ETM devices enabled after sink switch"
fi
fi
if [[ $source != "etm" ]]
then
stm_test_if_enabled
retval=$?
if [ $retval -eq 0 ]
then
echo "PASS: STM Enabled after sink switch"
fi
fi
if [[ $source != "stm" ]]
then
etm_disable_all_cores
fi
if [[ $source != "etm" ]]
then
stm_disable
fi
echo "----- Coresight Sink Switching Test Complete-----"
echo "-------------------------------------------------"
echo ""
@@ -0,0 +1,16 @@
LOCAL_PATH := $(call my-dir)
define ADD_TEST
include $(CLEAR_VARS)
LOCAL_MODULE := $1
LOCAL_SRC_FILES := $1
LOCAL_MODULE_CLASS := EXECUTABLE
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests/coresight/core/stm
include $(BUILD_PREBUILT)
endef
TEST_LIST := stm_disable.sh stm_enable.sh stm_etf_dump.sh stm_etr_dump.sh
$(foreach TEST,$(TEST_LIST),$(eval $(call ADD_TEST,$(TEST))))
@@ -0,0 +1,46 @@
#! /bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
echo "-----Coresight STM Disable Test Starting-----"
echo "---------------------------------------------"
source "$(dirname $0)/../cs_common.sh"
stm_disable
retval=$?
if [ $retval -eq 0 ]
then
stm_test_if_disabled
retval=$?
if [ $retval -eq 0 ]
then
echo "PASS: STM disabled"
fi
fi
echo "-----Coresight STM Disable Test Complete-----"
echo "---------------------------------------------"
echo ""
@@ -0,0 +1,47 @@
#! /bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
echo "-----Coresight STM Enable Test Starting-----"
echo "--------------------------------------------"
source "$(dirname $0)/../cs_common.sh"
stm_enable
retval=$?
if [ $retval -eq 0 ]
then
stm_test_if_enabled
retval=$?
if [ $retval -eq 0 ]
then
echo "PASS: STM Enabled"
fi
fi
echo "-----Coresight STM Enable Test Complete-----"
echo "--------------------------------------------"
echo ""
@@ -0,0 +1,79 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
echo "-----Coresight ETF Dump Test for STM Starting-----"
echo "--------------------------------------------------"
source "$(dirname $0)/../cs_common.sh"
stm_port=$stmpath"/port_enable"
stm_hwevent=$stmpath"/hwevent_enable"
if [ ! -d $debugfs ]
then
mkdir $debufgs
fi
mount -t debugfs nodev $debugfs 2>/dev/null
echo 0 > $debugfs"/tracing/events/enable"
#make etf current trace sink
echo 1 > $tmcetfpath"/curr_sink"
stm_enable
#disable hwevents when stm is enabled
echo 0 > $stm_hwevent
echo "stm-dump" > "/dev/coresight-stm"
stm_disable
if [ ! -d "/data/coresight-test" ]
then
mkdir -p "/data/coresight-test"
fi
cat "/dev/coresight-tmc-etf" > "/data/coresight-test/stm_etf.bin"
chmod a+x "/data/coresight-test/stm_etf.bin"
hexdump -ve '1/1 "%.2X"' "/data/coresight-test/stm_etf.bin" > "/data/coresight-test/stm_etf.txt"
brk=0
skip=0
size=0
while [ $brk -eq 0 ]
do
dd if="/data/coresight-test/stm_etf.txt" bs=1 skip=$skip count=16 of="/data/coresight-test/stm_etf.out" 2> /dev/null
if grep '0\{16\}' "/data/coresight-test/stm_etf.out" > /dev/null
then
brk=1
else
size=$(( size + 16 ))
fi
skip=$(( skip + 16 ))
done
if [ $size -eq 160 ]
then
echo "PASS: STM ETF dump test"
else
echo "FAIL: STM ETF dump test"
fi
rm -r "/data/coresight-test"
umount "/sys/kernel/debug" 2>/dev/null
echo "-----Coresight ETF Dump Test for STM Complete-----"
echo "--------------------------------------------------"
echo ""
@@ -0,0 +1,79 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
echo "-----Coresight ETR Dump Test for STM Starting-----"
echo "--------------------------------------------------"
source "$(dirname $0)/../cs_common.sh"
stm_port=$stmpath"/port_enable"
stm_hwevent=$stmpath"/hwevent_enable"
if [ ! -d $debugfs ]
then
mkdir $debufgs
fi
mount -t debugfs nodev $debugfs 2>/dev/null
echo 0 > $debugfs"/tracing/events/enable"
#make etr current trace sink
echo 1 > $tmcetrpath"/curr_sink"
stm_enable
#disable hwevents when stm is enabled
echo 0 > $stm_hwevent
echo "stm-dump" > "/dev/coresight-stm"
stm_disable
if [ ! -d "/data/coresight-test" ]
then
mkdir -p "/data/coresight-test"
fi
cat "/dev/coresight-tmc-etr" > "/data/coresight-test/stm_etr.bin"
chmod a+x "/data/coresight-test/stm_etr.bin"
hexdump -ve '1/1 "%.2X"' "/data/coresight-test/stm_etr.bin" > "/data/coresight-test/stm_etr.txt"
brk=0
skip=0
size=0
while [ $brk -eq 0 ]
do
dd if="/data/coresight-test/stm_etr.txt" bs=1 skip=$skip count=16 of="/data/coresight-test/stm_etr.out" 2> /dev/null
if grep '0\{16\}' "/data/coresight-test/stm_etr.out" > /dev/null
then
brk=1
else
size=$(( size + 16 ))
fi
skip=$(( skip + 16 ))
done
if [ $size -eq 160 ]
then
echo "PASS: STM ETR dump test"
else
echo "FAIL: STM ETR dump test"
fi
rm -r "/data/coresight-test"
umount "/sys/kernel/debug" 2>/dev/null
echo "-----Coresight ETR Dump Test for STM Complete-----"
echo "--------------------------------------------------"
echo ""
@@ -0,0 +1,39 @@
ifeq ($(call is-vendor-board-platform,QCOM),true)
ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH := $(call my-dir)
commonSources :=
# the dlkm
DLKM_DIR := device/qcom/common/dlkm
include $(CLEAR_VARS)
LOCAL_MODULE := msm_ion_test_module.ko
LOCAL_MODULE_TAGS := debug
include $(DLKM_DIR)/AndroidKernelModule.mk
# the userspace test program
include $(CLEAR_VARS)
LOCAL_MODULE := msm_iontest
LOCAL_SRC_FILES += $(commonSources) msm_iontest.c kernel_ion_tests.c user_ion_tests.c cp_ion_tests.c
LOCAL_SRC_FILES += ion_test_utils.c
LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include/
LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_SHARED_LIBRARIES := \
libc \
libcutils \
libutils
LOCAL_MODULE_TAGS := optional debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests
include $(BUILD_EXECUTABLE)
# the test script
include $(CLEAR_VARS)
LOCAL_MODULE := iontest.sh
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := iontest.sh
LOCAL_MODULE_TAGS := optional debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests
include $(BUILD_PREBUILT)
endif
endif
@@ -0,0 +1 @@
obj-m := msm_ion_test_module.o
@@ -0,0 +1,29 @@
iondir = $(prefix)/ion
ion_PROGRAMS = msm_iontest
msm_iontest_SOURCES = msm_iontest.c cp_ion_tests.c ion_test_utils.c kernel_ion_tests.c user_ion_tests.c
dist_ion_SCRIPTS = iontest.sh run.sh
KERNEL_FLAGS ?= ARCH=arm
module = msm_ion_test_module.ko
kmake = $(MAKE) $(KERNEL_FLAGS) -C $(KERNEL_DIR) M=$(CURDIR)
$(module):
$(kmake) modules
all-local: $(module)
install-exec-local: $(module)
$(kmake) INSTALL_MOD_PATH=$(DESTDIR)$(prefix)/modules modules_install
dist_ion_DATA = README.txt $(module)
# "make distclean" will always run clean-local in this directory,
# regardless of the KERNELMODULES conditional. Therefore, ensure
# KERNEL_DIR exists before running clean. Further, don't fail even
# if there is a problem.
clean-local:
-test ! -d "$(KERNEL_DIR)" || $(kmake) clean
@@ -0,0 +1,20 @@
Test: iontest
Usage: iontest [OPTIONS]...
OPTIONS can be (defaults in parenthesis):
-n, --nominal nominal test cases
-a, --adversarial adversarial test cases
-V run with debug messages on (off)
Description:
Ion is a memory allocator used by multimedia clients.
This test simulates a ion client to exercise the allocator framework
The ion framework provides, kernel space and user space interfaces.
Ion apis : linux/msm_ion.h and linux/ion.h
For running tests, the iontest.sh script should be used.
The script loads msm_ion_test_module kernel module.
This module is used to drive kernel space ion test cases.
Target support: 8960, 8930, 8064, 8974
@@ -0,0 +1,351 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* MSM ION content protection tests. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <sys/types.h>
#include <ctype.h>
#include <linux/input.h>
#include <linux/msm_ion.h>
#include <sys/mman.h>
#include "ion_test_plan.h"
#include "ion_test_utils.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static struct ion_test_data mm_heap_test = {
.align = 0x1000,
.size = 0x1000,
.heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID),
.flags = ION_FLAG_SECURE,
.heap_type_req = CP,
};
static struct ion_test_data adv_mm_heap_test = {
.align = 0x1000,
.size = 0x1000,
.heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID),
.heap_type_req = CP,
.flags = 0,
};
static struct ion_test_data *mm_heap_data_settings[] = {
[NOMINAL_TEST] = &mm_heap_test,
[ADV_TEST] = &adv_mm_heap_test,
};
static int test_sec_alloc(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_fd, ion_kernel_fd, map_fd, rc;
unsigned long addr;
struct ion_allocation_data alloc_data, sec_alloc_data;
struct ion_fd_data fd_data;
struct ion_test_data ktest_data;
struct ion_test_data *test_data;
struct ion_test_data **test_data_table =
(struct ion_test_data **)ion_tp->test_plan_data;
if (test_type == NOMINAL_TEST)
test_data = test_data_table[NOMINAL_TEST];
else
test_data = test_data_table[ADV_TEST];
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
ion_fd = open(ion_dev, O_RDONLY);
if (ion_fd < 0) {
debug(INFO, "Failed to open ion device\n");
perror("msm ion");
return ion_fd;
}
ion_kernel_fd = open(msm_ion_dev, O_RDONLY);
if (ion_kernel_fd < 0) {
debug(INFO, "Failed to open msm ion test device\n");
perror("msm ion");
close(ion_fd);
return ion_kernel_fd;
}
alloc_data.len = test_data->size;
alloc_data.align = test_data->align;
alloc_data.heap_mask = test_data->heap_mask;
alloc_data.flags = ION_SECURE;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
debug(ERR, "alloc buf failed\n");
goto cp_alloc_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_SEC, NULL);
if (rc) {
debug(INFO, "unable to secure heap\n");
goto cp_alloc_sec_err;
}
sec_alloc_data.len = test_data->size;
sec_alloc_data.heap_mask = test_data->heap_mask;
sec_alloc_data.flags = test_data->flags;
sec_alloc_data.align = test_data->align;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &sec_alloc_data);
if (rc < 0 && test_type == NOMINAL_TEST) {
debug(ERR, "Nominal cp alloc buf failed\n");
goto cp_alloc_sec_err;
} else if (rc < 0 && test_type == ADV_TEST) {
rc = 0;
goto cp_alloc_sec_err;
} else if (rc == 0 && test_type == ADV_TEST) {
debug(INFO, "erroneous alloc request succeeded\n");
rc = -EIO;
ioctl(ion_fd, ION_IOC_FREE, &sec_alloc_data.handle);
goto cp_alloc_sec_err;
} else {
ioctl(ion_fd, ION_IOC_FREE, &sec_alloc_data.handle);
}
ioctl(ion_kernel_fd, IOC_ION_UNSEC, NULL);
if (test_type == ADV_TEST) {
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);
if (rc < 0) {
debug(INFO, "unable to ion map buffer\n");
goto cp_alloc_sec_err;
}
map_fd = fd_data.fd;
addr = (unsigned long)mmap(NULL, alloc_data.len,
PROT_READ | PROT_WRITE,
MAP_SHARED , map_fd, 0);
sec_alloc_data.flags |= ION_FLAG_SECURE;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &sec_alloc_data);
if (rc == 0) {
rc = -EIO;
debug(INFO, "Sec alloc succeded with umapped buf\n");
ioctl(ion_fd, ION_IOC_FREE, &sec_alloc_data.handle);
close(fd_data.fd);
goto cp_alloc_sec_err;
}
close(fd_data.fd);
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc) {
debug(INFO, "failed to create kernel client\n");
goto cp_alloc_sec_err;
}
rc = ioctl(ion_fd, ION_IOC_SHARE, &fd_data);
if (rc < 0) {
debug(INFO, "unable to share ion buffer\n");
goto cp_alloc_sec_err;
}
ktest_data.align = test_data->align;
ktest_data.size = test_data->size;
ktest_data.heap_mask = test_data->heap_mask;
ktest_data.flags = test_data->flags;
ktest_data.shared_fd = fd_data.fd;
rc = ioctl(ion_kernel_fd, IOC_ION_UIMPORT, &ktest_data);
if (rc) {
debug(INFO, "unable to import ubuf to kernel space\n");
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
goto cp_alloc_sec_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KMAP, NULL);
if (rc) {
debug(INFO, "unable to map ubuf to kernel space\n");
ioctl(ion_kernel_fd, IOC_ION_KFREE, NULL);
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
goto cp_alloc_sec_err;
}
rc = ioctl(ion_fd, ION_IOC_ALLOC, &sec_alloc_data);
if (rc == 0) {
rc = -EIO;
ioctl(ion_fd, ION_IOC_FREE, &sec_alloc_data.handle);
debug(INFO, "Sec alloc succeded with kmapped buf\n");
}
ioctl(ion_kernel_fd, IOC_ION_KUMAP, NULL);
ioctl(ion_kernel_fd, IOC_ION_KFREE, NULL);
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
close(fd_data.fd);
}
cp_alloc_sec_err:
ioctl(ion_fd, ION_IOC_FREE, &alloc_data.handle);
cp_alloc_err:
close(ion_kernel_fd);
close(ion_fd);
out:
return rc;
}
static struct ion_test_plan sec_alloc_test = {
.name = "CP ion alloc buf",
.test_plan_data = &mm_heap_data_settings,
.test_plan_data_len = 3,
.test_type_flags = NOMINAL_TEST | ADV_TEST,
.test_fn = test_sec_alloc,
};
static int test_sec_map(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_fd, rc, ion_kernel_fd, map_fd;
unsigned long addr;
struct ion_allocation_data alloc_data;
struct ion_fd_data fd_data;
struct ion_test_data *test_data, ktest_data;
struct ion_test_data **test_data_table =
(struct ion_test_data **)ion_tp->test_plan_data;
if (test_type == NOMINAL_TEST)
test_data = test_data_table[NOMINAL_TEST];
else
test_data = test_data_table[ADV_TEST];
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
ion_fd = open(ion_dev, O_RDONLY);
if (ion_fd < 0) {
debug(INFO, "Failed to open ion device\n");
perror("msm ion");
return -EIO;
}
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(INFO, "Failed to open msm ion test device\n");
perror("msm ion");
close(ion_fd);
return -EIO;
}
alloc_data.len = test_data->size;
alloc_data.align = test_data->align;
alloc_data.heap_mask = test_data->heap_mask;
alloc_data.flags = test_data->flags;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
debug(INFO, "Failed to allocate uspace ion buffer\n");
goto sec_map_alloc_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_SEC, NULL);
if (rc) {
debug(INFO, "unable to secure heap\n");
goto sec_map_alloc_err;
}
debug(INFO, "passed secure heap\n");
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);
if (rc == 0) {
if (test_type == ADV_TEST) {
debug(ERR, "mapping buffer to uspace succeeded\n");
rc = -EIO;
close(fd_data.fd);
goto sec_map_err;
}
}
map_fd = fd_data.fd;
addr = (unsigned long)mmap(NULL, alloc_data.len,
PROT_READ | PROT_WRITE,
MAP_SHARED, map_fd, 0);
rc = ioctl(ion_fd, ION_IOC_SHARE, &fd_data);
if (rc) {
debug(INFO, "unable to share user buffer\n");
goto sec_map_share_err;
}
debug(INFO, "shared user buffer\n");
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc) {
debug(INFO, "failed to create kernel client\n");
goto sec_map_kc_err;
}
ktest_data.align = test_data->align;
ktest_data.size = test_data->size;
ktest_data.heap_mask = test_data->heap_mask;
ktest_data.flags = test_data->flags;
ktest_data.shared_fd = fd_data.fd;
rc = ioctl(ion_kernel_fd, IOC_ION_UIMPORT, &ktest_data);
if (rc) {
debug(INFO, "unable to import ubuf to kernel space\n");
goto sec_map_uimp_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KMAP, NULL);
if (rc == 0 && test_type == ADV_TEST) {
rc = -EIO;
debug(INFO, "able to map ubuf to kernel space\n");
ioctl(ion_kernel_fd, IOC_ION_KUMAP, NULL);
} else if (rc < 0) {
rc = 0;
} else {
ioctl(ion_kernel_fd, IOC_ION_KUMAP, NULL);
}
ioctl(ion_kernel_fd, IOC_ION_KFREE, NULL);
sec_map_uimp_err:
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
sec_map_kc_err:
close(fd_data.fd);
sec_map_share_err:
munmap((void *)addr, alloc_data.len);
sec_map_err:
ioctl(ion_kernel_fd, IOC_ION_UNSEC, NULL);
sec_map_alloc_err:
ioctl(ion_fd, ION_IOC_FREE, &alloc_data.handle);
close(ion_kernel_fd);
close(ion_fd);
out:
return rc;
}
static struct ion_test_plan sec_map_test = {
.name = "CP ion map test",
.test_plan_data = mm_heap_data_settings,
.test_plan_data_len = 3,
.test_type_flags = NOMINAL_TEST,
.test_fn = test_sec_map,
};
static struct ion_test_plan *cp_tests[] = {
&sec_alloc_test,
&sec_map_test,
};
struct ion_test_plan **get_cp_ion_tests(const char *dev, size_t *size)
{
*size = ARRAY_SIZE(cp_tests);
setup_heaps_for_tests(dev, cp_tests, *size);
return cp_tests;
}
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* MSM ION test plan */
#ifndef __ION_TEST_PLAN_
#define __ION_TEST_PLAN_
/*
* Test types
*/
#define NOMINAL_TEST 1
#define ADV_TEST 2
struct ion_test_plan {
const char *name;
void *test_plan_data;
unsigned int test_plan_data_len;
unsigned long test_type_flags;
int (*test_fn)(const char *ion_dev, const char *msm_ion_test,
struct ion_test_plan *, int test_type, int *skipped);
};
struct ion_test_plan **get_kernel_ion_tests(const char *dev, size_t *size);
struct ion_test_plan **get_user_ion_tests(const char *dev, size_t *size);
struct ion_test_plan **get_cp_ion_tests(const char *dev, size_t *size);
#endif
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* MSM ION test Utils. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <linux/input.h>
#include <linux/msm_ion.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "ion_test_plan.h"
#include "ion_test_utils.h"
int debug_level = ERR;
void set_debug_level(int level)
{
debug_level = level;
}
char *itoa(int num, char *buf, size_t len)
{
if (snprintf(buf, len, "%d", num) == -1)
return NULL;
else
return buf;
}
int sock_write(int fd, const char *buf, int size)
{
int sent = 0, wc = 0;
int index = 0;
const char *data = buf;
while (sent < size) {
wc = write(fd, &data[sent], size - sent);
if (wc < 0) {
debug(INFO, "\n error in writing to socket\n");
return -EIO;
} else {
sent += wc;
}
};
return 0;
}
int sock_read(int fd, char *buf, int size)
{
int rc = 0, rd = 0;
int index = 0;
char *data = buf;
while (rd < size) {
rc = read(fd, &data[rd], size - rd);
if (rc < 0) {
debug(INFO, "\n error in reading from socket\n");
return -EIO;
} else {
rd += rc;
}
}
return 0;
}
static int get_heap_data(const char *msm_ion_dev, struct ion_test_data *data)
{
int ion_kernel_fd, rc;
struct ion_heap_data heap_data;
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
heap_data.type = data->heap_type_req;
heap_data.heap_mask = data->heap_mask;
rc = ioctl(ion_kernel_fd, IOC_ION_FIND_PROPER_HEAP, &heap_data);
if (!rc) {
data->valid = heap_data.valid;
data->heap_mask = heap_data.heap_mask;
} else {
data->valid = 0;
}
close(ion_kernel_fd);
return rc;
}
void setup_heaps_for_tests(const char *dev, struct ion_test_plan **tp_array,
unsigned int len)
{
unsigned int i;
unsigned int j;
struct ion_test_plan *tp;
for (i = 0; i < len; ++i) {
tp = tp_array[i];
for (j = 0; j < tp->test_plan_data_len; ++j) {
struct ion_test_data *test_data;
if (tp->test_plan_data_len > 1) {
struct ion_test_data **test_data_table =
tp->test_plan_data;
test_data = test_data_table[j];
} else {
test_data = tp->test_plan_data;
}
if (test_data)
get_heap_data(dev, test_data);
}
}
}
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* MSM ION test utils */
#ifndef __ION_TEST_UTILS_
#define __ION_TEST_UTILS_
#include <stdint.h>
#include "iontest.h"
/* Debug level */
#define ERR 0
#define INFO 1
extern int debug_level;
#define debug(level, x...) do { (level > debug_level) ? 0 : printf(x); } \
while (0)
void set_debug_level(int level);
int sock_read(int sock_fd, char *buf, int size);
int sock_write(int sock_fd, const char *buf, int size);
char *itoa(int num, char *buf, size_t len);
void setup_heaps_for_tests(const char *dev, struct ion_test_plan **tp_array,
unsigned int len);
#endif
@@ -0,0 +1,90 @@
#ifndef __MSM_ION_TEST__
#define __MSM_ION_TEST__
#include <linux/ioctl.h>
enum ion_test_heap_type {
SYSTEM_MEM = 1, /* SYSTEM_HEAP */
SYSTEM_MEM2, /* IOMMU_HEAP */
SYSTEM_CONTIG,
CARVEOUT,
CP_CARVEOUT,
CP,
};
struct ion_test_data {
unsigned int align;
unsigned int size;
enum ion_test_heap_type heap_type_req;
unsigned long heap_mask; /* Auto-detected if possible */
unsigned long flags;
unsigned long vaddr;
unsigned long cache;
int shared_fd;
unsigned int valid; /* Valid for this target. Auto-detected */
};
struct ion_heap_data {
enum ion_test_heap_type type;
unsigned int size;
unsigned long heap_mask;
unsigned int valid;
};
#define MSM_ION_MAGIC 'M'
#define IOC_ION_KCLIENT_CREATE _IO(MSM_ION_MAGIC, 0)
#define IOC_ION_KCLIENT_DESTROY _IO(MSM_ION_MAGIC, 1)
#define IOC_ION_KALLOC _IOW(MSM_ION_MAGIC, 2, struct ion_test_data)
#define IOC_ION_KFREE _IO(MSM_ION_MAGIC, 3)
#define IOC_ION_KPHYS _IO(MSM_ION_MAGIC, 4)
#define IOC_ION_KMAP _IO(MSM_ION_MAGIC, 5)
#define IOC_ION_KUMAP _IO(MSM_ION_MAGIC, 6)
#define IOC_ION_UIMPORT _IOW(MSM_ION_MAGIC, 7, struct ion_test_data)
#define IOC_ION_WRITE_VERIFY _IO(MSM_ION_MAGIC, 8)
#define IOC_ION_VERIFY _IO(MSM_ION_MAGIC, 9)
#define IOC_ION_UBUF_FLAGS _IOR(MSM_ION_MAGIC, 10, unsigned long)
#define IOC_ION_UBUF_SIZE _IOR(MSM_ION_MAGIC, 11, unsigned long)
#define IOC_ION_SEC _IO(MSM_ION_MAGIC, 12)
#define IOC_ION_UNSEC _IO(MSM_ION_MAGIC, 13)
#define IOC_ION_FIND_PROPER_HEAP _IOWR(MSM_ION_MAGIC, 14, struct ion_heap_data)
static inline void write_pattern(unsigned long buf, size_t size)
{
uint8_t *addr = (uint8_t *)buf;
uint8_t count = 0;
unsigned int i;
for (i = 0; i < size; i++) {
addr[i] = count;
if (count == 0xFF)
count = 0;
else
count++;
}
}
static inline int verify_pattern(unsigned long buf, size_t size)
{
uint8_t *addr = (uint8_t *)buf;
uint8_t count = 0;
unsigned int i;
for (i = 0; i < size; i++) {
if (addr[i] != count)
return -EIO;
if (count == 0xFF)
count = 0;
else
count++;
}
return 0;
}
#endif
+107
View File
@@ -0,0 +1,107 @@
# Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Unit test for the ion.
#
# Invoked by run.sh
# This will run nominal and adversarial testcases.
chmod 755 msm_iontest
if [ -d /system/lib/modules/ ]; then
modpath=/system/lib/modules
else
modpath=/kernel-tests/modules/lib/modules/$(uname -r)/extra
fi
ion_test_mod=${modpath}/msm_ion_test_module.ko
ion_dev=/dev/ion
ion_dev_misc=/sys/class/misc/ion/dev
ion_test_dev=/dev/msm_ion_test
ion_test_dev_sys=/sys/class/msm_ion_test/msm_ion_test/dev
test_type=n
level=0
maybe_make_node()
{
thedev=$1
themisc=$2
[ -e $thedev ] || \
mknod $thedev c $(cut -d: -f1 $themisc) $(cut -d: -f2 $themisc)
}
for i in $*
do
case $i in
-n | --nominal)
# already nominal test case by default
;;
-a | --adversarial)
test_type=a
;;
-V)
level=1
;;
-h | --help | *)
echo "Usage: $0 [-n | --nominal] [-a | --adversarial] [-V]";
exit 1
;;
esac
done
# create ion device if it doesn't exist
maybe_make_node $ion_dev $ion_dev_misc
if [ ! -e $ion_test_mod ]; then
echo "ERROR: Kernel Test Module not present"
exit 1
fi
# insert msm_ion_test_module if needed
if [ ! -e $ion_test_dev_sys ]; then
insmod $ion_test_mod
if [ $? -ne 0 ]; then
echo "ERROR: failed to load module $ion_test_mod"
exit 1
fi
fi
# create the ion test device if it doesn't exist
maybe_make_node $ion_test_dev $ion_test_dev_sys
#invoke test
./msm_iontest $test_type $level
ret=$?
if [ $ret -ne 0 ];then
echo "Test Failed"
else
echo "Test Passed"
fi
rmmod msm_ion_test_module
exit $ret
@@ -0,0 +1,676 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* MSM ION Kernel api tests. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <sys/types.h>
#include <ctype.h>
#include <linux/input.h>
#include <linux/msm_ion.h>
#include <sys/mman.h>
#include "ion_test_plan.h"
#include "ion_test_utils.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static struct ion_test_data mm_heap_test = {
.align = 0x1000,
.size = 0x1000,
.heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID),
.heap_type_req = SYSTEM_MEM,
.flags = ION_FLAG_CACHED,
};
static struct ion_test_data phys_heap_test = {
.align = 0x1000,
.size = 0x1000,
.heap_mask = ION_HEAP(ION_QSECOM_HEAP_ID),
.heap_type_req = CARVEOUT,
.flags = 0,
};
static struct ion_test_data adv_mm_heap_test = {
.align = 0x1000,
.size = 0xC0000000,
.heap_mask = ION_HEAP(ION_QSECOM_HEAP_ID),
.heap_type_req = CARVEOUT,
.flags = 0,
};
static struct ion_test_data adv_system_heap_test = {
.align = 0x1000,
.size = 0x1000,
.heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID),
.heap_type_req = SYSTEM_MEM,
.flags = 0,
};
static struct ion_test_data *mm_heap_data_settings[] = {
[NOMINAL_TEST] = &mm_heap_test,
[ADV_TEST] = &adv_mm_heap_test,
};
/*
* Kernel ion client create test
*/
int test_kclient(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_kernel_fd, rc;
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc < 0) {
debug(ERR, "kernel client create failed\n");
return -EIO;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
close(ion_kernel_fd);
*test_skipped = 0;
return 0;
}
static struct ion_test_plan kclient_test = {
.name = "Kernel ion client",
.test_type_flags = NOMINAL_TEST,
.test_plan_data_len = 0,
.test_fn = test_kclient,
};
/*
* Kernel ion buf alloc
* Nominal test: Using mm heap.
* ADV test: Invalid client, and erroneous alloc request
*/
int test_kalloc(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_kernel_fd, rc;
struct ion_test_data *test_data;
struct ion_test_data **test_data_table =
(struct ion_test_data **)ion_tp->test_plan_data;
if (test_type == NOMINAL_TEST)
test_data = test_data_table[NOMINAL_TEST];
else
test_data = test_data_table[ADV_TEST];
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc < 0) {
debug(ERR, "kernel client create failed\n");
close(ion_kernel_fd);
return -EIO;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KALLOC, test_data);
if (rc < 0 && test_type == NOMINAL_TEST) {
debug(ERR, "Nominal kernel alloc buf failed\n");
goto alloc_err;
} else if (rc < 0 && test_type == ADV_TEST) {
rc = 0;
goto alloc_err;
} else if (rc == 0 && test_type == ADV_TEST) {
debug(INFO, "erroneous alloc request succeeded\n");
rc = EIO;
}
ioctl(ion_kernel_fd, IOC_ION_KFREE, NULL);
alloc_err:
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
close(ion_kernel_fd);
out:
return rc;
}
static struct ion_test_plan kalloc_test = {
.name = "Kernel ion alloc buf",
.test_plan_data = mm_heap_data_settings,
.test_plan_data_len = 3,
.test_type_flags = NOMINAL_TEST | ADV_TEST,
.test_fn = test_kalloc,
};
/*
* Kernel ion phys attr
* Nominal test: use mm heap settings
* Adeveserial test: Invalid handle and client
*/
int test_kphys(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_kernel_fd, rc;
struct ion_test_data *test_data =
(struct ion_test_data *)ion_tp->test_plan_data;
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
/*
* ADV test 1: invalid client
* TODO: Requires fix in ion_phys
* Currently causes a creash
*/
if (test_type == ADV_TEST) {
rc = ioctl(ion_kernel_fd, IOC_ION_KPHYS, NULL);
if (!rc) {
debug(INFO, "phys attr obtained with invalid handle\n");
rc = -EIO;
close(ion_kernel_fd);
return rc;
}
}
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc < 0) {
debug(ERR, "kernel client create failed\n");
goto n_kphys_kc_err;
}
/*
* ADV test 2: invalid handle
* TODO: Requires fix in ion_phys
* Currently causes a creash
*/
if (test_type == ADV_TEST) {
rc = ioctl(ion_kernel_fd, IOC_ION_KPHYS, NULL);
if (!rc) {
debug(INFO, "phys attr obtained with invalid handle\n");
rc = -EIO;
goto n_kphys_alloc_err;
}
}
rc = ioctl(ion_kernel_fd, IOC_ION_KALLOC, test_data);
if (rc < 0) {
debug(ERR, "kernel alloc buf failed\n");
goto n_kphys_alloc_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KPHYS, NULL);
ioctl(ion_kernel_fd, IOC_ION_KFREE, NULL);
n_kphys_alloc_err:
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
n_kphys_kc_err:
close(ion_kernel_fd);
out:
return rc;
}
static struct ion_test_plan kphys_test = {
.name = "Kernel ion buf phys attr test",
.test_plan_data = &phys_heap_test,
.test_plan_data_len = 1,
/*
* TODO: Enable ADV test after ion phys api
* can handle erroneous input
*/
.test_type_flags = NOMINAL_TEST,
.test_fn = test_kphys,
};
/*
* Kernel ion system phys attr
* Adeveserial test: get phys attr from system heap
*/
int test_ksystem_phys(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_kernel_fd, rc;
struct ion_test_data *test_data =
(struct ion_test_data *)ion_tp->test_plan_data;
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc < 0) {
debug(ERR, "kernel client create failed\n");
goto n_kphys_kc_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KALLOC, test_data);
if (rc < 0) {
debug(ERR, "kernel system alloc buf failed\n");
goto n_kphys_alloc_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KPHYS, NULL);
if (rc < 0 && test_type == ADV_TEST)
rc = 0;
ioctl(ion_kernel_fd, IOC_ION_KFREE, NULL);
n_kphys_alloc_err:
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
n_kphys_kc_err:
close(ion_kernel_fd);
out:
return rc;
}
static struct ion_test_plan ksystem_test = {
.name = "Kernel system buf phys attr test",
.test_plan_data = &adv_system_heap_test,
.test_plan_data_len = 1,
.test_type_flags = ADV_TEST,
.test_fn = test_ksystem_phys,
};
/*
* Kernel ion map
*/
int test_kmap(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
*test_skipped = 0;
if (test_type == NOMINAL_TEST) {
int ion_kernel_fd, rc;
struct ion_test_data *test_data =
(struct ion_test_data *)ion_tp->test_plan_data;
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc < 0) {
debug(ERR, "kernel client create failed\n");
goto n_kmap_kc_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KALLOC, test_data);
if (rc < 0) {
debug(ERR, "kernel alloc buf failed\n");
goto n_kmap_alloc_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KMAP, NULL);
if (!rc) {
rc = ioctl(ion_kernel_fd, IOC_ION_WRITE_VERIFY, NULL);
if (rc < 0)
debug(ERR, "kernel map verification fails\n");
ioctl(ion_kernel_fd, IOC_ION_KUMAP, NULL);
}
ioctl(ion_kernel_fd, IOC_ION_KFREE, NULL);
n_kmap_alloc_err:
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
n_kmap_kc_err:
close(ion_kernel_fd);
return rc;
}
out:
return 0;
}
static struct ion_test_plan kmap_test = {
.name = "Kernel ion map test",
.test_plan_data = &mm_heap_test,
.test_plan_data_len = 1,
.test_type_flags = NOMINAL_TEST,
.test_fn = test_kmap,
};
/*
* Kernel ion user import test
*/
int test_kuimport(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_kernel_fd, rc, ion_fd, map_fd;
struct ion_allocation_data alloc_data;
struct ion_fd_data fd_data;
unsigned long addr;
struct ion_test_data *test_data =
(struct ion_test_data *)ion_tp->test_plan_data;
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc < 0) {
debug(ERR, "kernel client create failed\n");
close(ion_kernel_fd);
return -EIO;
}
ion_fd = open(ion_dev, O_RDONLY);
if (ion_fd < 0) {
debug(ERR, "Failed to open ion device\n");
perror("msm ion");
rc = -EIO;
goto kuimp_id_err;
}
if (test_type == ADV_TEST) {
rc = ioctl(ion_kernel_fd, IOC_ION_UIMPORT, &ion_fd);
if (rc < 0)
rc = 0;
else
rc = -EIO;
goto kuimp_adv_test_close;
}
if (test_type == NOMINAL_TEST) {
alloc_data.len = test_data->size;
alloc_data.align = test_data->align;
alloc_data.heap_mask = test_data->heap_mask;
alloc_data.flags = test_data->flags;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
debug(ERR, "Failed to allocate uspace ion buffer\n");
goto kuimp_adv_test_close;
}
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);
if (rc) {
debug(ERR, "Failed to map uspace ion buffer\n");
goto kuimp_map_err;
}
map_fd = fd_data.fd;
addr = (unsigned long)mmap(NULL, alloc_data.len,
PROT_READ | PROT_WRITE,
MAP_SHARED , map_fd, 0);
write_pattern(addr, alloc_data.len);
rc = ioctl(ion_fd, ION_IOC_SHARE, &fd_data);
if (rc) {
debug(ERR, "Failed to share uspace ion buffer fd\n");
goto kuimp_share_err;
}
test_data->shared_fd = fd_data.fd;
rc = ioctl(ion_kernel_fd, IOC_ION_UIMPORT, test_data);
if (!rc) {
rc = ioctl(ion_kernel_fd, IOC_ION_KMAP, NULL);
if (!rc)
rc = ioctl(ion_kernel_fd, IOC_ION_VERIFY, NULL);
else
debug(ERR, "failed to map uimp buffer\n");
ioctl(ion_kernel_fd, IOC_ION_KUMAP, NULL);
ioctl(ion_kernel_fd, IOC_ION_KFREE, NULL);
}
if (rc)
debug(ERR, "Failed to import uspace buffer\n");
kuimp_share_err:
munmap((void *)addr, alloc_data.len);
close(map_fd);
kuimp_map_err:
ioctl(ion_fd, ION_IOC_FREE, &alloc_data.handle);
}
kuimp_adv_test_close:
close(ion_fd);
kuimp_id_err:
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
close(ion_kernel_fd);
out:
return rc;
}
static struct ion_test_plan kuimp_test = {
.name = "Kernel ion uspace buffer import",
.test_plan_data = &mm_heap_test,
.test_plan_data_len = 1,
.test_type_flags = ADV_TEST,
.test_fn = test_kuimport,
};
/*
* Kernel ion imported user buf attributes test
*/
int test_ubuf_attr(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
*test_skipped = 0;
if (test_type == NOMINAL_TEST) {
int ion_kernel_fd, rc, ion_fd, map_fd;
struct ion_allocation_data alloc_data;
struct ion_fd_data fd_data;
unsigned long addr, flags, size;
struct ion_test_data *test_data =
(struct ion_test_data *)ion_tp->test_plan_data;
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped (nom)\n",__func__);
goto out;
}
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc < 0) {
debug(ERR, "kernel client create failed\n");
close(ion_kernel_fd);
return -EIO;
}
ion_fd = open(ion_dev, O_RDONLY);
if (ion_fd < 0) {
debug(ERR, "Failed to open ion device\n");
perror("msm ion");
rc = -EIO;
goto kubuf_id_err;
}
alloc_data.len = test_data->size;
alloc_data.align = test_data->align;
alloc_data.heap_mask = test_data->heap_mask;
alloc_data.flags = test_data->flags;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
debug(ERR, "Failed to allocate uspace ion buffer\n");
goto n_kubuf_alloc_err;
}
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_SHARE, &fd_data);
if (rc) {
debug(ERR, "Failed to share uspace ion buffer fd\n");
goto n_kubuf_share_err;
}
test_data->shared_fd = fd_data.fd;
rc = ioctl(ion_kernel_fd, IOC_ION_UIMPORT, test_data);
if (!rc) {
rc = ioctl(ion_kernel_fd, IOC_ION_UBUF_FLAGS, &flags);
if (!rc)
rc = ioctl(ion_kernel_fd, IOC_ION_UBUF_SIZE,
&size);
else if (rc < 0) {
debug(ERR, "failed to get ubuf attributes\n");
} else {
rc = ((size == alloc_data.len) &&
(flags == alloc_data.flags)) ?
0 : -EIO;
}
ioctl(ion_kernel_fd, IOC_ION_KFREE, NULL);
} else
debug(ERR, "failed to import uspace buf\n");
close(fd_data.fd);
n_kubuf_share_err:
ioctl(ion_fd, ION_IOC_FREE, &alloc_data.handle);
n_kubuf_alloc_err:
close(ion_fd);
kubuf_id_err:
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
close(ion_kernel_fd);
return rc;
} else if (test_type == ADV_TEST) {
int ion_kernel_fd, rc, ion_fd, map_fd;
struct ion_allocation_data alloc_data;
struct ion_fd_data fd_data;
unsigned long addr, flags, size;
struct ion_test_data *test_data =
(struct ion_test_data *)ion_tp->test_plan_data;
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped (adv)\n",__func__);
goto out;
}
ion_kernel_fd = open(msm_ion_dev, O_RDWR);
if (ion_kernel_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
ion_fd = open(ion_dev, O_RDONLY);
if (ion_fd < 0) {
debug(ERR, "Failed to open ion device\n");
perror("msm ion");
close(ion_kernel_fd);
return -EIO;
}
alloc_data.len = test_data->size;
alloc_data.align = test_data->align;
alloc_data.heap_mask = test_data->heap_mask;
alloc_data.flags = test_data->flags;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
debug(ERR, "Failed to allocate uspace ion buffer\n");
goto a_kubuf_alloc_err;
}
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_SHARE, &fd_data);
if (rc) {
debug(ERR, "Failed to share uspace ion buffer fd\n");
goto a_kubuf_share_err;
}
test_data->shared_fd = fd_data.fd;
rc = ioctl(ion_kernel_fd, IOC_ION_UBUF_FLAGS, &flags);
if (rc)
rc = ioctl(ion_kernel_fd, IOC_ION_UBUF_SIZE, &size);
if (rc == 0) {
debug(INFO, "can read ubuf attr with invalid client\n");
goto a_kubuf_attr_client_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_KCLIENT_CREATE, NULL);
if (rc < 0) {
debug(INFO, "kernel client create failed\n");
goto a_kubuf_attr_client_err;
}
rc = ioctl(ion_kernel_fd, IOC_ION_UBUF_FLAGS, &flags);
if (rc)
rc = ioctl(ion_kernel_fd, IOC_ION_UBUF_SIZE, &size);
if (rc == 0) {
debug(INFO, "can read ubuf attr with invalid handle\n");
goto a_kubuf_attr_handle_err;
}
rc = 0;
a_kubuf_attr_handle_err:
ioctl(ion_kernel_fd, IOC_ION_KCLIENT_DESTROY, NULL);
a_kubuf_attr_client_err:
a_kubuf_share_err:
ioctl(ion_fd, ION_IOC_FREE, &alloc_data.handle);
a_kubuf_alloc_err:
close(ion_fd);
close(ion_kernel_fd);
}
out:
return 0;
}
static struct ion_test_plan kubuf_attr_test = {
.name = "Kernel ion uspace buffer size and flags",
.test_plan_data = &mm_heap_test,
.test_plan_data_len = 1,
/* TODO: ADV test causes crash in ion.
* Needs to be fixed till then ADV test
* diabled
*/
.test_type_flags = NOMINAL_TEST,
.test_fn = test_ubuf_attr,
};
static struct ion_test_plan *kernel_tests[] = {
&kclient_test,
&kalloc_test,
&kphys_test,
&ksystem_test,
&kmap_test,
&kuimp_test,
&kubuf_attr_test,
};
struct ion_test_plan **get_kernel_ion_tests(const char *dev, size_t *size)
{
*size = ARRAY_SIZE(kernel_tests);
setup_heaps_for_tests(dev, kernel_tests, *size);
return kernel_tests;
}
@@ -0,0 +1,450 @@
/* Copyright (c) 2012-2013, The Linux Foundation. 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 and
* only 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.
*/
#include <linux/init.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/msm_ion.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include "iontest.h"
#define ION_TEST_DEV_NAME "msm_ion_test"
#define CLIENT_NAME "ion_test_client"
struct msm_ion_test {
struct ion_client *ion_client;
struct ion_handle *ion_handle;
struct ion_test_data test_data;
};
struct heap {
unsigned int id;
unsigned int size;
enum ion_test_heap_type type;
};
static struct class *ion_test_class;
static int ion_test_major;
static struct device *ion_test_dev;
static struct heap *heap_list;
static unsigned int heap_list_len;
/*Utility apis*/
static inline int create_ion_client(struct msm_ion_test *ion_test)
{
ion_test->ion_client = msm_ion_client_create(UINT_MAX, CLIENT_NAME);
if (IS_ERR_OR_NULL(ion_test->ion_client))
return -EIO;
return 0;
}
static inline void free_ion_client(struct msm_ion_test *ion_test)
{
ion_client_destroy(ion_test->ion_client);
}
static int alloc_ion_buf(struct msm_ion_test *ion_test,
struct ion_test_data *test_data)
{
ion_test->ion_handle = ion_alloc(ion_test->ion_client, test_data->size,
test_data->align, test_data->heap_mask,
test_data->flags);
if (IS_ERR_OR_NULL(ion_test->ion_handle))
return -EIO;
return 0;
}
static inline void free_ion_buf(struct msm_ion_test *ion_test)
{
ion_free(ion_test->ion_client, ion_test->ion_handle);
}
static int heap_detected;
#ifdef CONFIG_OF_DEVICE
static int ion_find_heaps_available(void)
{
struct device_node *ion_node;
struct device_node *ion_child;
unsigned int i = 0;
int ret = 0;
unsigned int val = 0;
ion_node = of_find_compatible_node(NULL, NULL, "qcom,msm-ion");
for_each_child_of_node(ion_node, ion_child)
heap_list_len++;
heap_list = kzalloc(sizeof(struct heap) * heap_list_len, GFP_KERNEL);
if (!heap_list) {
ret = -ENOMEM;
goto out;
}
for_each_child_of_node(ion_node, ion_child) {
ret = of_property_read_u32(ion_child, "reg", &val);
if (ret) {
pr_err("%s: Unable to find reg key", __func__);
goto free_heaps;
}
heap_list[i].id = val;
switch (val) {
case ION_SYSTEM_HEAP_ID:
{
heap_list[i].type = SYSTEM_MEM;
break;
}
case ION_SYSTEM_CONTIG_HEAP_ID:
{
heap_list[i].type = SYSTEM_CONTIG;
break;
}
case ION_CP_MM_HEAP_ID:
{
ret = of_property_read_u32(ion_child,
"qcom,memory-reservation-size", &val);
if (ret) {
heap_list[i].type = CP;
} else {
heap_list[i].size = val;
heap_list[i].type = CP_CARVEOUT;
}
break;
}
case ION_IOMMU_HEAP_ID:
{
heap_list[i].type = SYSTEM_MEM2;
break;
}
case ION_QSECOM_HEAP_ID:
case ION_AUDIO_HEAP_ID:
{
ret = of_property_read_u32(ion_child,
"qcom,memory-reservation-size", &val);
if (ret) {
heap_list[i].type = 0;
} else {
heap_list[i].size = val;
heap_list[i].type = CARVEOUT;
}
break;
}
default:
break;
}
++i;
}
heap_detected = 1;
goto out;
free_heaps:
kfree(heap_list);
heap_list = 0;
out:
return ret;
}
#else
static int ion_find_heaps_available(void)
{
return 0;
}
#endif
static int ion_test_open(struct inode *inode, struct file *file)
{
struct msm_ion_test *ion_test = kzalloc(sizeof(struct msm_ion_test),
GFP_KERNEL);
if (!ion_test)
return -ENOMEM;
pr_debug("ion test device opened\n");
file->private_data = ion_test;
return ion_find_heaps_available();
}
static int get_proper_heap(struct ion_heap_data *data)
{
int ret = -EINVAL;
unsigned int i;
if (!heap_detected) {
data->valid = 1;
ret = 0;
} else {
data->heap_mask = 0;
data->size = 0;
data->valid = 0;
for (i = 0; i < heap_list_len; ++i) {
if (data->type == heap_list[i].type) {
data->size = heap_list[i].size;
data->heap_mask = ION_HEAP(heap_list[i].id);
data->valid = 1;
ret = 0;
break;
}
}
}
return ret;
}
static long ion_test_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
int ret;
ion_phys_addr_t phys_addr;
void *addr;
size_t len;
unsigned long flags, size;
struct msm_ion_test *ion_test = file->private_data;
struct ion_test_data *test_data = &ion_test->test_data;
switch (cmd) {
case IOC_ION_KCLIENT_CREATE:
{
ret = create_ion_client(ion_test);
break;
}
case IOC_ION_KCLIENT_DESTROY:
{
free_ion_client(ion_test);
ret = 0;
break;
}
case IOC_ION_KALLOC:
{
if (copy_from_user(test_data, (void __user *)arg,
sizeof(struct ion_test_data)))
return -EFAULT;
ret = alloc_ion_buf(ion_test, test_data);
if (ret)
pr_info("allocating ion buffer failed\n");
break;
}
case IOC_ION_KFREE:
{
free_ion_buf(ion_test);
ret = 0;
break;
}
case IOC_ION_KPHYS:
{
ret = ion_phys(ion_test->ion_client, ion_test->ion_handle,
&phys_addr, &len);
if (!ret)
pr_info("size is 0x%x\n phys addr 0x%x", len,
(unsigned int)phys_addr);
break;
}
case IOC_ION_KMAP:
{
addr = ion_map_kernel(ion_test->ion_client,
ion_test->ion_handle);
if (IS_ERR_OR_NULL(addr)) {
ret = -EIO;
pr_info("mapping kernel buffer failed\n");
} else {
ret = 0;
test_data->vaddr = (unsigned long)addr;
}
break;
}
case IOC_ION_KUMAP:
{
ion_unmap_kernel(ion_test->ion_client, ion_test->ion_handle);
ret = 0;
break;
}
case IOC_ION_UIMPORT:
{
if (copy_from_user(test_data, (void __user *)arg,
sizeof(struct ion_test_data)))
return -EFAULT;
ion_test->ion_handle = ion_import_dma_buf(ion_test->ion_client,
test_data->shared_fd);
if (IS_ERR_OR_NULL(ion_test->ion_handle)) {
ret = -EIO;
pr_info("import of user buf failed\n");
} else
ret = 0;
break;
}
case IOC_ION_UBUF_FLAGS:
{
ret = ion_handle_get_flags(ion_test->ion_client,
ion_test->ion_handle, &flags);
if (ret)
pr_info("user flags cannot be retrieved\n");
else
if (copy_to_user((void __user *)arg, &flags,
sizeof(unsigned long)))
ret = -EFAULT;
break;
}
case IOC_ION_UBUF_SIZE:
{
ret = ion_handle_get_size(ion_test->ion_client,
ion_test->ion_handle, &size);
if (ret)
pr_info("buffer size cannot be retrieved\n");
else
if (copy_to_user((void __user *)arg, &size,
sizeof(unsigned long)))
ret = -EFAULT;
break;
}
case IOC_ION_WRITE_VERIFY:
{
write_pattern(test_data->vaddr, test_data->size);
if (verify_pattern(test_data->vaddr, test_data->size)) {
pr_info("verify of mapped buf failed\n");
ret = -EIO;
} else
ret = 0;
break;
}
case IOC_ION_VERIFY:
{
if (verify_pattern(test_data->vaddr, test_data->size)) {
pr_info("fail in verifying imported buffer\n");
ret = -EIO;
} else
ret = 0;
break;
}
case IOC_ION_SEC:
{
ret = msm_ion_secure_heap(ION_CP_MM_HEAP_ID);
if (ret)
pr_info("unable to secure heap\n");
else
pr_info("able to secure heap\n");
break;
}
case IOC_ION_UNSEC:
{
ret = msm_ion_unsecure_heap(ION_CP_MM_HEAP_ID);
if (ret)
pr_info("unable to unsecure heap\n");
else
pr_info("able to unsecure heap\n");
break;
}
case IOC_ION_FIND_PROPER_HEAP:
{
struct ion_heap_data data;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_heap_data)))
return -EFAULT;
ret = get_proper_heap(&data);
if (!ret) {
if (copy_to_user((void __user *)arg, &data,
sizeof(struct ion_heap_data)))
ret = -EFAULT;
}
break;
}
default:
{
pr_info("command not supported\n");
ret = -EINVAL;
}
};
return ret;
}
static int ion_test_release(struct inode *inode, struct file *file)
{
struct msm_ion_test *ion_test = file->private_data;
pr_debug("ion test device closed\n");
kfree(ion_test);
return 0;
}
/*
* Register ourselves as a device to be able to test the ion code
* from userspace.
*/
static const struct file_operations ion_test_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = ion_test_ioctl,
.open = ion_test_open,
.release = ion_test_release,
};
static int ion_test_device_create(void)
{
int ret_val = 0;
ion_test_major = register_chrdev(0, ION_TEST_DEV_NAME, &ion_test_fops);
if (ion_test_major < 0) {
pr_err("Unable to register chrdev: %d\n", ion_test_major);
ret_val = ion_test_major;
goto out;
}
ion_test_class = class_create(THIS_MODULE, ION_TEST_DEV_NAME);
if (IS_ERR(ion_test_class)) {
ret_val = PTR_ERR(ion_test_class);
pr_err("Unable to create class: %d\n", ret_val);
goto err_create_class;
}
ion_test_dev = device_create(ion_test_class, NULL, MKDEV(ion_test_major, 0), NULL, ION_TEST_DEV_NAME);
if (IS_ERR(ion_test_dev)) {
ret_val = PTR_ERR(ion_test_dev);
pr_err("Unable to create device: %d\n", ret_val);
goto err_create_device;
}
goto out;
err_create_device:
class_destroy(ion_test_class);
err_create_class:
unregister_chrdev(ion_test_major, ION_TEST_DEV_NAME);
out:
return ret_val;
}
static void ion_test_device_destroy(void)
{
device_destroy(ion_test_class, MKDEV(ion_test_major, 0));
class_destroy(ion_test_class);
unregister_chrdev(ion_test_major, ION_TEST_DEV_NAME);
kfree(heap_list);
}
static int ion_test_init(void)
{
return ion_test_device_create();
}
static void ion_test_exit(void)
{
return ion_test_device_destroy();
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Test for MSM ION implementation");
module_init(ion_test_init);
module_exit(ion_test_exit);
@@ -0,0 +1,197 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* MSM ION tester. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <sys/types.h>
#include <ctype.h>
#include <linux/input.h>
#include <linux/msm_ion.h>
#include <linux/kernel.h>
#include <sys/mman.h>
#include "ion_test_plan.h"
#include "ion_test_utils.h"
/* Device path names */
#define MSM_ION_TEST "/dev/msm_ion_test"
#define MSM_ION "/dev/ion"
unsigned int TEST_TYPE = NOMINAL_TEST;
static int run_tests(struct ion_test_plan **table, const char *test_plan,
unsigned int type, size_t size,
unsigned int *total_tests,
unsigned int *tests_skipped)
{
struct ion_test_plan *test;
unsigned int i;
int ret = 0;
int skipped = 0;
for (i = 0; i < size; i++) {
test = table[i];
if (!test) {
printf("%s test table size mismatch\n", test_plan);
break;
}
if (test->test_type_flags & type) {
ret = test->test_fn(MSM_ION, MSM_ION_TEST, test,
type, &skipped);
if (ret) {
debug(INFO, "%s test failed, stopping\n",
test->name);
break;
} else {
debug(INFO, "%s test passed\n", test->name);
}
++(*total_tests);
if (skipped)
++(*tests_skipped);
}
}
return ret;
}
int parse_args(int argc, char **argv)
{
unsigned int level;
if (argc != 3)
return 1;
switch (argv[1][0]) {
case 'n':
{
TEST_TYPE = NOMINAL_TEST;
break;
}
case 'a':
{
TEST_TYPE = ADV_TEST;
break;
}
default:
return -EINVAL;
}
level = atoi(argv[2]);
if (level != INFO && level != ERR)
return -EINVAL;
set_debug_level(level);
return 0;
}
int main(int argc, char **argv)
{
unsigned int i = 0, type;
int ret = 0;
size_t usize, ksize, cpsize;
struct ion_test_plan **utable, **ktable, **cptable;
unsigned int total_tests_run = 0;
unsigned int total_skipped = 0;
if (parse_args(argc, argv)) {
debug(ERR, "incorrect arguments passed\n");
return -EINVAL;
}
/* Get test tables */
utable = get_user_ion_tests(MSM_ION_TEST, &usize);
if (!utable) {
debug(ERR, "no user tests\n");
return -EIO;
}
ktable = get_kernel_ion_tests(MSM_ION_TEST, &ksize);
if (!ktable) {
debug(ERR, "no kernel tests\n");
return -EIO;
}
cptable = get_cp_ion_tests(MSM_ION_TEST, &cpsize);
if (!cptable) {
debug(ERR, "no user tests\n");
return -EIO;
}
/* Run tests */
if (TEST_TYPE == NOMINAL_TEST) {
debug(INFO, "\n\nRunning Nominal user space ion tests :\n\n");
ret = run_tests(utable, "user space", NOMINAL_TEST, usize,
&total_tests_run, &total_skipped);
if (ret) {
debug(INFO, "user space Nominal tests failed\n");
return ret;
}
type = NOMINAL_TEST;
debug(INFO, "\n\nRunning Nominal kernel space ion tests :\n\n");
ret = run_tests(ktable, "kernel space", type, ksize,
&total_tests_run, &total_skipped);
if (ret) {
debug(INFO, "kernel space Nominal tests failed\n");
return ret;
}
debug(INFO, "\n\nRunning Nominal cp ion tests :\n\n");
ret = run_tests(cptable, "CP", type, cpsize,
&total_tests_run, &total_skipped);
if (ret) {
debug(INFO, "cp ion Nominal tests failed\n");
return ret;
}
}
if (TEST_TYPE == ADV_TEST) {
type = ADV_TEST;
debug(INFO, "\n\nRunning Adversarial user space ion tests:\n");
ret = run_tests(utable, "user space", type, usize,
&total_tests_run, &total_skipped);
if (ret) {
debug(INFO, "user space Adversarial tests failed\n");
return ret;
}
debug(INFO,
"\n\nRunning Adversarial kernel space ion tests:\n");
ret = run_tests(ktable, "kernel space", type, ksize,
&total_tests_run, &total_skipped);
if (ret) {
debug(INFO, "kernel space Adversarial tests failed\n");
return ret;
}
debug(INFO, "\n\nRunning Adversarial cp ion tests :\n\n");
ret = run_tests(cptable, "CP", type, cpsize,
&total_tests_run, &total_skipped);
if (ret) {
debug(INFO, "cp ion Adversarial tests failed\n");
return ret;
}
}
printf("Ran %u tests out of which %u were skipped\n",
total_tests_run, total_skipped);
return ret;
}
+32
View File
@@ -0,0 +1,32 @@
#! /bin/sh --
# Copyright (c) 2012, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
cd `dirname $0` && exec ./iontest.sh $@
@@ -0,0 +1,457 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* MSM ION User space tests. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <malloc.h>
#include <linux/input.h>
#include <linux/msm_ion.h>
#include <linux/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/types.h>
#include "ion_test_plan.h"
#include "ion_test_utils.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static struct ion_test_data mm_heap_test = {
.align = 0x1000,
.size = 0x1000,
.heap_type_req = SYSTEM_MEM2,
.heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID),
};
static struct ion_test_data adv_mm_heap_test = {
.align = 0x1000,
.size = 0xC0000000,
.heap_type_req = CARVEOUT,
.heap_mask = ION_HEAP(ION_QSECOM_HEAP_ID),
};
static struct ion_test_data *mm_heap_data_settings[] = {
[NOMINAL_TEST] = &mm_heap_test,
[ADV_TEST] = &adv_mm_heap_test,
};
static int test_ualloc(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_fd, rc;
struct ion_allocation_data alloc_data;
struct ion_test_data *test_data;
struct ion_test_data **test_data_table =
(struct ion_test_data **)ion_tp->test_plan_data;
if (test_type == NOMINAL_TEST)
test_data = test_data_table[NOMINAL_TEST];
else
test_data = test_data_table[ADV_TEST];
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
ion_fd = open(ion_dev, O_RDONLY);
if (ion_fd < 0) {
debug(ERR, "Failed to open msm ion test device\n");
perror("msm ion");
return -EIO;
}
alloc_data.len = test_data->size;
alloc_data.align = test_data->align;
alloc_data.heap_mask = test_data->heap_mask;
alloc_data.flags = test_data->flags;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc < 0 && test_type == NOMINAL_TEST) {
debug(ERR, "Nominal user alloc buf failed\n");
perror("msm ion");
goto ualloc_err;
} else if (rc < 0 && test_type == ADV_TEST) {
rc = 0;
goto ualloc_err;
} else if (rc == 0 && test_type == ADV_TEST) {
debug(INFO, "erroneous alloc request succeeded\n");
rc = -EIO;
}
ioctl(ion_fd, ION_IOC_FREE, &alloc_data.handle);
ualloc_err:
close(ion_fd);
out:
return rc;
}
static struct ion_test_plan ualloc_test = {
.name = "User ion alloc buf",
.test_plan_data = mm_heap_data_settings,
.test_plan_data_len = 3,
.test_type_flags = NOMINAL_TEST | ADV_TEST,
.test_fn = test_ualloc,
};
static int test_umap(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_fd, map_fd, rc;
void *addr;
struct ion_allocation_data alloc_data;
struct ion_fd_data fd_data;
struct ion_test_data *test_data =
(struct ion_test_data *)ion_tp->test_plan_data;
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
ion_fd = open(ion_dev, O_RDONLY);
if (ion_fd < 0) {
debug(INFO, "Failed to open ion device\n");
perror("msm ion");
return -EIO;
}
alloc_data.len = test_data->size;
alloc_data.align = test_data->align;
alloc_data.heap_mask = test_data->heap_mask;
alloc_data.flags = test_data->flags;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
debug(ERR, "Failed to allocate uspace ion buffer\n");
goto umap_alloc_err;
}
/*
* ADV TEST1: Use invalid handle
*/
if (test_type == ADV_TEST) {
rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);
if (!rc) {
debug(INFO, "mapped using invalid handle\n");
rc = -EIO;
goto umap_map_err;
}
}
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);
if (rc < 0) {
debug(INFO, "unable to ion map buffer\n");
goto umap_map_err;
}
map_fd = fd_data.fd;
/*
* ADV test2: map twice the allocted length
*/
if (test_type == ADV_TEST) {
addr = mmap(NULL, alloc_data.len * 2,
PROT_READ | PROT_WRITE,
MAP_SHARED, map_fd, 0);
if (!addr) {
debug(INFO, "mmap succeded using larger map length\n");
munmap(addr, alloc_data.len * 2);
rc = -EIO;
goto umap_map_err;
}
}
addr = mmap(NULL, alloc_data.len,
PROT_READ | PROT_WRITE,
MAP_SHARED, map_fd, 0);
if (!addr) {
debug(INFO, "mmap failed\n");
goto umap_map_err;
}
write_pattern((unsigned long)addr, alloc_data.len);
if (verify_pattern((unsigned long)addr, alloc_data.len)) {
debug(INFO, "mapped buffer not writeable\n");
rc = -EIO;
} else
rc = 0;
munmap(addr, alloc_data.len);
close(map_fd);
ioctl(ion_fd, ION_IOC_FREE, &alloc_data.handle);
/*
* Nominal Test with alloc length / 2
*/
alloc_data.len = test_data->size * 2;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
debug(ERR, "Failed to allocate uspace ion buffer\n");
goto umap_alloc_err;
}
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);
if (rc < 0) {
debug(INFO, "unable to ion map buffer\n");
goto umap_map_err;
}
map_fd = fd_data.fd;
addr = mmap(NULL, alloc_data.len/2,
PROT_READ | PROT_WRITE,
MAP_SHARED, map_fd, 0);
if (!addr) {
debug(INFO, "mmap failed\n");
close(map_fd);
goto umap_map_err;
}
write_pattern((unsigned long)addr, alloc_data.len/2);
if (verify_pattern((unsigned long)addr, alloc_data.len/2)) {
debug(INFO, "mapped buffer not writeable\n");
rc = -EIO;
} else
rc = 0;
munmap(addr, alloc_data.len/2);
close(map_fd);
umap_map_err:
ioctl(ion_fd, ION_IOC_FREE, &alloc_data.handle);
umap_alloc_err:
close(ion_fd);
out:
return rc;
}
static struct ion_test_plan umap_test = {
.name = "User ion buf map",
.test_plan_data = &mm_heap_test,
.test_plan_data_len = 1,
.test_type_flags = NOMINAL_TEST | ADV_TEST,
.test_fn = test_umap,
};
static int uimport_ion_buf(int fd)
{
static char cbuf[100];
int ion_fd, size, rc;
void *addr;
struct ion_fd_data fd_data;
debug(INFO, "importing data in child done\n");
/* receive buf fd */
if (-EIO == sock_read(fd, cbuf, sizeof(int)*8))
return -EIO;
fd_data.fd = atoi(cbuf);
/* receive buf length */
if (-EIO == sock_read(fd, cbuf, sizeof(int)*8))
return -EIO;
size = atoi(cbuf);
/* receive ion dev name */
if (-EIO == sock_read(fd, cbuf, sizeof(cbuf)))
return -EIO;
ion_fd = open(cbuf, O_RDONLY);
if (ion_fd < 1) {
debug(INFO, "unable to open ion device\n");
rc = -EINVAL;
goto child_args_err;
}
rc = ioctl(ion_fd, ION_IOC_IMPORT, &fd_data);
if (rc) {
debug(INFO, "ION_IOC_IMPORT failed\n");
rc = -EIO;
goto child_imp_err;
}
addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd_data.fd, 0);
if (!addr) {
debug(INFO, "failed to map buffer\n");
rc = -EIO;
goto child_mmap_err;
}
if (verify_pattern((unsigned long)addr, (size_t)size)) {
debug(INFO, "unable to verify imported buffer\n");
rc = -EIO;
} else
debug(INFO, "import test passed\n");
munmap(addr, size);
child_mmap_err:
close(fd_data.fd);
ioctl(ion_fd, ION_IOC_FREE, &fd_data.handle);
child_imp_err:
close(ion_fd);
child_args_err:
itoa(rc, cbuf, sizeof(int)*8);
child_sock_err:
close(fd);
return rc;
}
static int uimp_spawn_process(pid_t *pid, int *wr_fd)
{
int socket[2], child;
if (pipe(socket) < 0) {
debug(INFO, "unable to create pipe\n");
return -EIO;
}
child = fork();
if (child == -1) {
debug(INFO, "unable to fork process\n");
return -EIO;
} else if (child == 0) {
close(socket[1]);
if (uimport_ion_buf(socket[0]))
exit(1) ;
exit(0);
} else {
*pid = child;
close(socket[0]);
*wr_fd = socket[1];
return 0;
}
}
static int test_uimp(const char *ion_dev, const char *msm_ion_dev,
struct ion_test_plan *ion_tp, int test_type,
int *test_skipped)
{
int ion_fd, map_fd, rc, wr_fd;
int sock_fd;
char buf[32];
void *addr;
struct ion_allocation_data alloc_data;
struct ion_fd_data fd_data;
int child_status;
static char ubuf[100];
pid_t tpid, child_pid;
struct ion_test_data *test_data =
(struct ion_test_data *)ion_tp->test_plan_data;
*test_skipped = !test_data->valid;
if (!test_data->valid) {
rc = 0;
debug(INFO, "%s was skipped\n",__func__);
goto out;
}
rc = uimp_spawn_process(&child_pid, &wr_fd);
if (rc)
return -EIO;
ion_fd = open(ion_dev, O_RDONLY);
if (ion_fd < 0) {
debug(INFO, "Failed to open ion device\n");
perror("msm ion");
return -EIO;
}
alloc_data.len = test_data->size;
alloc_data.align = test_data->align;
alloc_data.heap_mask = test_data->heap_mask;
alloc_data.flags = test_data->flags;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
debug(INFO, "Failed to allocate uspace ion buffer\n");
goto uimp_alloc_err;
}
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);
if (rc < 0) {
debug(INFO, "unable to ion map buffer\n");
goto uimp_map_err;
}
map_fd = fd_data.fd;
addr = mmap(NULL, alloc_data.len,
PROT_READ | PROT_WRITE,
MAP_SHARED , map_fd, 0);
if (!addr) {
debug(INFO, "mmap failed\n");
rc = -EIO;
goto uimp_mmap_err;
}
write_pattern((unsigned long)addr, alloc_data.len);
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_SHARE, &fd_data);
if (rc < 0) {
debug(INFO, "unable to share ion buffer\n");
goto uimp_share_err;
}
if (test_type == NOMINAL_TEST)
itoa(fd_data.fd, ubuf, sizeof(int) * 8);
else
itoa(ion_fd, ubuf, sizeof(int) * 8);
if (-EIO == sock_write(wr_fd, ubuf, sizeof(int) * 8))
goto uimp_sock_err;
itoa(alloc_data.len, ubuf, sizeof(int) * 8);
if (-EIO == sock_write(wr_fd, ubuf, sizeof(int) * 8))
goto uimp_sock_err;
strncpy(ubuf, ion_dev, sizeof(ubuf));
if (-EIO == sock_write(wr_fd, ubuf, sizeof(ubuf)))
goto uimp_sock_err;
do {
tpid = wait(&child_status);
} while (tpid != child_pid);
if (test_type == NOMINAL_TEST && child_status != 0)
rc = child_status;
else if (test_type == ADV_TEST && child_status == 0)
rc = -EIO;
else
rc = 0;
uimp_sock_err:
close(fd_data.fd);
uimp_share_err:
munmap(addr, alloc_data.len);
uimp_mmap_err:
close(map_fd);
uimp_map_err:
ioctl(ion_fd, ION_IOC_FREE, &alloc_data.handle);
uimp_alloc_err:
close(ion_fd);
close(wr_fd);
out:
return rc;
}
static struct ion_test_plan uimp_test = {
.name = "User ion import test ",
.test_plan_data = &mm_heap_test,
.test_plan_data_len = 1,
.test_type_flags = ADV_TEST,
.test_fn = test_uimp,
};
static struct ion_test_plan *user_tests[] = {
&ualloc_test,
&umap_test,
&uimp_test,
};
struct ion_test_plan **get_user_ion_tests(const char *dev, size_t *size)
{
*size = ARRAY_SIZE(user_tests);
setup_heaps_for_tests(dev, user_tests, *size);
return user_tests;
}
@@ -0,0 +1,37 @@
ifeq ($(call is-vendor-board-platform,QCOM),true)
ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH := $(call my-dir)
# the dlkm
DLKM_DIR := device/qcom/common/dlkm
include $(CLEAR_VARS)
LOCAL_MODULE := the_memory_prof_module.ko
LOCAL_MODULE_TAGS := debug
include $(DLKM_DIR)/AndroidKernelModule.mk
# the userspace test program
include $(CLEAR_VARS)
LOCAL_MODULE := memory_prof
LOCAL_SRC_FILES += memory_prof.c
LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include/
LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_SHARED_LIBRARIES := \
libc \
libcutils \
libutils
LOCAL_MODULE_TAGS := optional debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests
include $(BUILD_EXECUTABLE)
# the test script
include $(CLEAR_VARS)
LOCAL_MODULE := memory_prof.sh
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := memory_prof.sh
LOCAL_MODULE_TAGS := optional debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests
include $(BUILD_PREBUILT)
endif
endif
@@ -0,0 +1,3 @@
obj-m := the_memory_prof_module.o
the_memory_prof_module-y := memory_prof_module.o timing_debug.o
@@ -0,0 +1,26 @@
memory_profdir = $(prefix)/memory_prof
memory_prof_PROGRAMS = memory_prof
memory_prof_SOURCES = memory_prof.c
memory_prof_CFLAGS = -lm
dist_memory_prof_SCRIPTS = memory_prof.sh run.sh
KERNEL_FLAGS ?= ARCH=arm
all_modules = the_memory_prof_module.ko
kmake = $(MAKE) $(KERNEL_FLAGS) -C $(KERNEL_DIR) M=$(CURDIR)
the_memory_prof_module.ko: memory_prof_module.c timing_debug.c
$(kmake) modules
all-local: $(all_modules)
install-exec-local: $(all_modules)
$(kmake) INSTALL_MOD_PATH=$(DESTDIR)$(prefix)/modules modules_install
# "make distclean" will always run clean-local in this directory,
# regardless of the KERNELMODULES conditional. Therefore, ensure
# KERNEL_DIR exists before running clean. Further, don't fail even
# if there is a problem.
clean-local:
-test ! -d "$(KERNEL_DIR)" || $(kmake) clean
@@ -0,0 +1,35 @@
Test: memory_prof
Usage: memory_prof [OPTIONS]...
OPTIONS:
-h Print this message and exit
-a Do the adversarial test (same as -l)
-b Do basic sanity tests
-e Do Ion heap profiling
-k Do kernel alloc profiling (requires kernel module)
-l Do leak test (leak an ion handle)
-m Do map extra test (requires kernel module)
-n Do the nominal test (same as -b)
-o Do OOM test (alloc from Ion Iommu heap until OOM)
-p MS Sleep for MS milliseconds between stuff (for debugging)
-r Do the repeatability test
-s Do the stress test (same as -e)
Description:
These tests are useful for catching performance regressions in Ion or
general memory code (using the -e and -k options). They can also catch
other Ion regressions by performing some basic sanity tests (the -b,
-m, and -l options).
Notes:
This test suite is accompanied by a kernel module that must be
inserted for certain test cases (namely -k and -m). The memory_prof.sh
script will take care of inserting the kernel module and running the
memory_prof binary for you. However, sometimes it's useful to be able
run the memory_prof binary directly without inserting the kernel
module.
Target support: 8974
@@ -0,0 +1,894 @@
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <libgen.h> /* for basename */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/queue.h>
#include <linux/msm_ion.h>
#include <memory_prof_module.h>
#define NUM_REPS_FOR_HEAP_PROFILING 100
#define NUM_REPS_FOR_REPEATABILITY 100
#define ION_PRE_ALLOC_SIZE_DEFAULT 0 //0 MB
#define MAX_PRE_ALLOC_SIZE 5000 // 5000 MB
#define MEMORY_PROF_DEV "/dev/memory_prof"
#define ION_DEV "/dev/ion"
/*
* Don't change the format of the following line strings. We need to
* rely on them for parsing.
*/
#define ST_PREFIX_DATA_ROW "=> "
#define ST_PREFIX_PREALLOC_SIZE "==> "
#define ST_PREFIX_NUM_REPS "===> "
#define SZ_1K 0x00000400
#define SZ_2K 0x00000800
#define SZ_4K 0x00001000
#define SZ_8K 0x00002000
#define SZ_16K 0x00004000
#define SZ_32K 0x00008000
#define SZ_64K 0x00010000
#define SZ_128K 0x00020000
#define SZ_256K 0x00040000
#define SZ_512K 0x00080000
#define SZ_1M 0x00100000
#define SZ_2M 0x00200000
#define SZ_4M 0x00400000
#define SZ_8M 0x00800000
#define SZ_16M 0x01000000
#define SZ_32M 0x02000000
#define SZ_64M 0x04000000
#define SZ_128M 0x08000000
#define SZ_256M 0x10000000
#define SZ_512M 0x20000000
static unsigned int sleepiness;
static void sleepy()
{
usleep(sleepiness);
}
static void print_n_slow(char *st)
{
puts(st);
sleepy();
}
static void hr()
{
puts("---------------");
}
/**
* @ionfd [out] ion fd. On success, user must close.
* @alloc_data [in/out] alloc data. On success, user must free.
* returns 0 on success, 1 otherwise
*/
static int alloc_me_up_some_ion(int *ionfd,
struct ion_allocation_data *alloc_data)
{
int rc = 0;
*ionfd = open(ION_DEV, O_RDONLY);
if (*ionfd < 0) {
perror("couldn't open " ION_DEV);
return *ionfd;
}
rc = ioctl(*ionfd, ION_IOC_ALLOC, alloc_data);
if (rc) {
perror("couldn't do ion alloc");
close(*ionfd);
}
return rc;
}
static int basic_ion_sanity_test(struct ion_allocation_data alloc_data,
unsigned long size_mb)
{
uint8_t *buf;
int ionfd, rc;
unsigned long i, squelched = 0;
bool integrity_good = true;
struct ion_fd_data fd_data;
struct ion_custom_data custom_data;
struct ion_flush_data flush_data;
rc = alloc_me_up_some_ion(&ionfd, &alloc_data);
if (rc)
goto out;
fd_data.handle = alloc_data.handle;
rc = ioctl(ionfd, ION_IOC_MAP, &fd_data);
if (rc) {
perror("couldn't do ION_IOC_MAP");
goto err1;
}
buf = mmap(NULL, size_mb, PROT_READ | PROT_WRITE, MAP_SHARED,
fd_data.fd, 0);
if (buf == MAP_FAILED) {
perror("couldn't do mmap");
rc = (int) MAP_FAILED;
goto err2;
}
memset(buf, 0xA5, size_mb);
flush_data.handle = alloc_data.handle;
flush_data.vaddr = buf;
flush_data.length = size_mb;
custom_data.cmd = ION_IOC_CLEAN_INV_CACHES;
custom_data.arg = (unsigned long) &flush_data;
if (ioctl(ionfd, ION_IOC_CUSTOM, &custom_data)) {
perror("Couldn't flush caches");
rc = 1;
goto err3;
} else {
puts("flushed caches");
}
for (i = 0; i < size_mb; ++i) {
if (buf[i] != 0xA5) {
if (!integrity_good) {
squelched++;
continue;
}
printf(" Data integrity error at "
"offset 0x%x from 0x%p!!!!\n", i, buf);
integrity_good = false;
}
}
if (squelched)
printf(" (squelched %d additional integrity error%s)\n",
squelched, squelched == 1 ? "" : "s");
if (integrity_good)
printf(" Buffer integrity check succeeded\n");
err3:
if (munmap(buf, size_mb)) {
rc = 1;
perror("couldn't do munmap");
}
err2:
close(fd_data.fd);
err1:
rc |= ioctl(ionfd, ION_IOC_FREE, &alloc_data.handle);
err0:
close(ionfd);
out:
return rc;
}
static void basic_sanity_tests(unsigned long size_mb)
{
int lrc, rc = 0;
struct ion_allocation_data iommu_alloc_data = {
.align = SZ_1M,
.len = SZ_1M,
.heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID),
.flags = 0,
};
struct ion_allocation_data system_alloc_data = {
.align = SZ_1M,
.len = SZ_1M,
.heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID),
.flags = 0,
};
struct ion_allocation_data system_contig_alloc_data = {
.align = SZ_1M,
.len = SZ_1M,
.heap_mask = ION_HEAP(ION_SYSTEM_CONTIG_HEAP_ID),
.flags = 0,
};
puts("testing IOMMU without caching...");
lrc = basic_ion_sanity_test(iommu_alloc_data, size_mb);
puts(lrc ? "FAILED!" : "PASSED");
hr();
sleepy();
rc |= lrc;
puts("testing IOMMU with caching...");
iommu_alloc_data.flags |= ION_FLAG_CACHED;
lrc = basic_ion_sanity_test(iommu_alloc_data, size_mb);
puts(lrc ? "FAILED!" : "PASSED");
hr();
sleepy();
rc |= lrc;
puts("testing system without caching (should fail)...");
lrc = !basic_ion_sanity_test(system_alloc_data, size_mb);
puts(lrc ? "FAILED! (failed to fail)" : "PASSED (successfully failed)");
hr();
sleepy();
rc |= lrc;
puts("testing system with caching...");
system_alloc_data.flags |= ION_FLAG_CACHED;
lrc = basic_ion_sanity_test(system_alloc_data, size_mb);
puts(lrc ? "FAILED!" : "PASSED");
hr();
sleepy();
rc |= lrc;
puts("testing system contig without caching (should fail)...");
lrc = !basic_ion_sanity_test(system_contig_alloc_data, size_mb);
puts(lrc ? "FAILED! (failed to fail)" : "PASSED (successfully failed)");
hr();
sleepy();
rc |= lrc;
puts("testing system contig with caching...");
system_contig_alloc_data.flags |= ION_FLAG_CACHED;
lrc = basic_ion_sanity_test(system_contig_alloc_data, size_mb);
puts(lrc ? "FAILED!" : "PASSED");
hr();
sleepy();
rc |= lrc;
if (rc)
puts("BASIC SANITY TESTS FAILED!!!!!!!! WOOOWWWW!!!!!!");
else
puts("All basic sanity tests passed");
}
static int do_map_extra_test(void)
{
int rc = 0;
int ionfd, memory_prof_fd;
struct memory_prof_map_extra_args args;
size_t buffer_length = SZ_1M;
struct ion_allocation_data alloc_data = {
.align = SZ_1M,
.len = buffer_length,
.heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID),
.flags = 0,
};
struct ion_fd_data fd_data;
memory_prof_fd = open(MEMORY_PROF_DEV, 0);
if (memory_prof_fd < 0) {
perror("couldn't open " MEMORY_PROF_DEV);
rc = memory_prof_fd;
goto out;
}
rc = ioctl(memory_prof_fd, MEMORY_PROF_IOC_CLIENT_CREATE);
if (rc) {
perror("couldn't do MEMORY_PROF_IOC_CLIENT_CREATE");
goto close_memory_prof_fd;
}
rc = alloc_me_up_some_ion(&ionfd, &alloc_data);
if (rc)
goto destroy_ion_client;
fd_data.handle = alloc_data.handle;
rc = ioctl(ionfd, ION_IOC_SHARE, &fd_data);
if (rc) {
perror("Couldn't do ION_IOC_SHARE");
goto ion_free_and_close;
}
args.ionfd = fd_data.fd;
args.iommu_map_len = buffer_length * 2;
print_n_slow("Doing MEMORY_PROF_IOC_TEST_MAP_EXTRA");
rc = ioctl(memory_prof_fd, MEMORY_PROF_IOC_TEST_MAP_EXTRA, &args);
if (rc) {
perror("couldn't do MEMORY_PROF_IOC_TEST_MAP_EXTRA");
goto ion_free_and_close;
}
ion_free_and_close:
rc |= ioctl(ionfd, ION_IOC_FREE, &alloc_data.handle);
close(ionfd);
destroy_ion_client:
rc |= ioctl(memory_prof_fd, MEMORY_PROF_IOC_CLIENT_DESTROY);
close_memory_prof_fd:
close(memory_prof_fd);
out:
return rc;
}
#define US_TO_MS(us) (us / 1000)
#define MS_TO_S(ms) (ms / 1000)
#define S_TO_MS(s) (s * 1000)
#define MS_TO_US(ms) (ms * 1000)
#define S_TO_US(s) (s * 1000 * 1000)
/**
* timeval_sub - subtracts t2 from t1
*
* Returns a timeval with the result
*/
static struct timeval timeval_sub(struct timeval t1, struct timeval t2)
{
struct timeval diff;
diff.tv_sec = t1.tv_sec - t2.tv_sec;
if (t1.tv_usec < t2.tv_usec) {
diff.tv_usec = t1.tv_usec + S_TO_US(1) - t2.tv_usec;
diff.tv_sec--;
} else {
diff.tv_usec = t1.tv_usec - t2.tv_usec;
}
return diff;
}
/**
* timeval_ms_diff - gets the difference (in MS) between t1 and t2
*
* Returns the MS diff between t1 and t2 (t2 - t1)
*/
static long timeval_ms_diff(struct timeval t1, struct timeval t2)
{
struct timeval tv_result = timeval_sub(t1, t2);
return US_TO_MS(tv_result.tv_usec) + S_TO_MS(tv_result.tv_sec);
}
/**
* Free memory in alloc_list
*/
void free_mem_list(char **alloc_list)
{
int i = 0;
for (i = 0; i < MAX_PRE_ALLOC_SIZE; i++) {
if (alloc_list[i] != NULL) {
free(alloc_list[i]);
alloc_list[i] = NULL;
}
}
}
/**
* Allocate sizemb in alloc_list
*/
int alloc_mem_list(char **alloc_list, int sizemb)
{
int i = 0;
int alloc_size = 1*1024*1024 * sizeof(char);
if (sizemb > MAX_PRE_ALLOC_SIZE) {
return -1;
}
// Break allocation into 1 MB pieces to ensure
// we easily find enough virtually contigous memory
for (i = 0; i < sizemb; i++)
{
alloc_list[i] =(char *) malloc(alloc_size);
if (alloc_list[i] == NULL)
{
perror("couldn't allocate 1MB");
free_mem_list(alloc_list);
return -1;
}
// Memory must be accessed for it to be page backed.
// We may want to randomize the data in the future
// to prevent features such as KSM returning memory
// to the system.
memset(alloc_list[i], 1, alloc_size);
}
return 0;
}
/**
* Returns the total time taken for ION_IOC_ALLOC
*
* @heap_mask - passed to ION_IOC_ALLOC
* @flags - passed to ION_IOC_ALLOC
* @size - passed to ION_IOC_ALLOC
* @quiet - whether we should suppress alloc failures
* @pre_alloc_size - size of memory to malloc before doing the ion alloc
* @alloc_ms - [output] time taken to complete the ION_IOC_ALLOC
* @free_ms - [output] time taken to complete the ION_IOC_FREE
*
* Returns 0 on success, 1 on failure.
*/
static int profile_alloc_for_heap(unsigned int heap_mask,
unsigned int flags, unsigned int size,
bool quiet,
int pre_alloc_size,
long *alloc_ms, long *free_ms)
{
long ms = -1;
int ionfd, rc, rc2;
struct timeval tv_before, tv_after, tv_result;
struct ion_allocation_data alloc_data = {
.align = SZ_4K,
.len = size,
.heap_mask = heap_mask,
.flags = flags,
};
char *pre_alloc_list[MAX_PRE_ALLOC_SIZE];
memset(pre_alloc_list, 0, MAX_PRE_ALLOC_SIZE * sizeof(char *));
*alloc_ms = 0;
*free_ms = 0;
if (alloc_mem_list(pre_alloc_list, pre_alloc_size) < 0) {
perror("couldn't create pre-allocated buffer");
goto out;
}
ionfd = open(ION_DEV, O_RDONLY);
if (ionfd < 0) {
perror("couldn't open " ION_DEV);
goto free_mem_list;
}
rc = gettimeofday(&tv_before, NULL);
if (rc) {
perror("couldn't get time of day");
goto close_ion;
}
rc2 = ioctl(ionfd, ION_IOC_ALLOC, &alloc_data);
rc = gettimeofday(&tv_after, NULL);
if (rc) {
perror("couldn't get time of day");
goto close_ion;
}
if (rc2) {
if (!quiet)
perror("couldn't do ion alloc");
rc = rc2;
goto close_ion;
}
*alloc_ms = timeval_ms_diff(tv_after, tv_before);
/*
* Okay, things are about to get messy. We're profiling our
* cleanup, but we might fail some stuff and need to
* cleanup... during cleanup.
*/
rc = gettimeofday(&tv_before, NULL);
if (rc)
perror("couldn't get time of day");
free:
ioctl(ionfd, ION_IOC_FREE, &alloc_data.handle);
rc2 = gettimeofday(&tv_after, NULL);
if (!rc) {
if (rc2) {
perror("couldn't get time of day");
goto close_ion;
}
*free_ms = timeval_ms_diff(tv_after, tv_before);
}
close_ion:
close(ionfd);
free_mem_list:
free_mem_list(pre_alloc_list);
out:
return rc;
}
static void map_extra_test(void)
{
int rc = 0;
puts("testing msm_iommu_map_extra...");
rc = do_map_extra_test();
if (rc) puts("FAILED!");
hr();
}
static void profile_kernel_alloc(void)
{
int rc, memory_prof_fd;
memory_prof_fd = open(MEMORY_PROF_DEV, 0);
if (memory_prof_fd < 0) {
perror("couldn't open " MEMORY_PROF_DEV);
return;
}
rc = ioctl(memory_prof_fd, MEMORY_PROF_IOC_TEST_KERNEL_ALLOCS);
if (rc)
perror("couldn't do MEMORY_PROF_IOC_TEST_KERNEL_ALLOCS");
close(memory_prof_fd);
}
static void print_stats_results(const char *name, const char *cached,
const char *size_string,
long alloc_stats[], int reps)
{
int i;
float sum = 0, sum_of_squares = 0, average, std_dev;
for (i = 0; i < reps; ++i) {
sum += alloc_stats[i];
}
average = sum / reps;
for (i = 0; i < reps; ++i) {
sum_of_squares += pow(alloc_stats[i] - average, 2);
}
std_dev = sqrt(sum_of_squares / reps);
printf(ST_PREFIX_DATA_ROW " %s %s %s average: %.2f std_dev: %.2f\n",
name, cached, size_string, average, std_dev);
}
static void heap_profiling(int pre_alloc_size, const int nreps)
{
int i;
struct sizes_struct {
unsigned long size;
const char *sMB;
bool quiet;
};
struct sizes_struct *szp;
struct sizes_struct sizes[] = {
{
.size = SZ_1M * 1,
.sMB = "1MB",
.quiet = false,
}, {
.size = SZ_1M * 3,
.sMB = "3MB",
.quiet = false,
}, {
.size = SZ_1M * 5,
.sMB = "5MB",
.quiet = false,
}, {
.size = SZ_1M * 8,
.sMB = "8MB",
.quiet = false,
}, {
.size = SZ_1M * 10,
.sMB = "10MB",
.quiet = false,
}, {
.size = SZ_1M * 13,
.sMB = "13MB",
.quiet = false,
}, {
.size = SZ_1M * 20,
.sMB = "20MB",
.quiet = false,
}, {
.size = SZ_1M * 50,
.sMB = "50MB",
.quiet = true,
}, {
.size = SZ_1M * 100,
.sMB = "100MB",
.quiet = true,
}, {
/* SENTINEL */
.size = 0,
}
};
puts("All times are in milliseconds unless otherwise indicated");
printf(ST_PREFIX_PREALLOC_SIZE "pre-alloc size (MB): %d\n",
pre_alloc_size);
printf(ST_PREFIX_NUM_REPS "num reps: %d\n", nreps);
for (szp = &sizes[0]; szp->size; ++szp) {
unsigned int sz = szp->size;
const char *sMB = szp->sMB;
bool quiet = szp->quiet;
long alloc_stats[nreps];
long free_stats[nreps];
printf("\n============PROFILING FOR %s MB=============\n",
sMB);
for (i = 0; i < nreps; ++i) {
profile_alloc_for_heap(
ION_HEAP(ION_CP_MM_HEAP_ID),
ION_SECURE, sz, quiet,
pre_alloc_size,
&alloc_stats[i], &free_stats[i]);
}
print_stats_results("ION_IOC_ALLOC ION_CP_MM_HEAP_ID",
"uncached", sMB,
alloc_stats, nreps);
print_stats_results("ION_IOC_FREE ION_CP_MM_HEAP_ID",
"uncached", sMB,
free_stats, nreps);
for (i = 0; i < nreps; ++i) {
profile_alloc_for_heap(
ION_HEAP(ION_IOMMU_HEAP_ID),
0, sz, quiet,
pre_alloc_size,
&alloc_stats[i], &free_stats[i]);
}
print_stats_results("ION_IOC_ALLOC ION_IOMMU_HEAP_ID",
"uncached", sMB,
alloc_stats, nreps);
print_stats_results("ION_IOC_FREE ION_IOMMU_HEAP_ID",
"uncached", sMB,
free_stats, nreps);
for (i = 0; i < nreps; ++i) {
profile_alloc_for_heap(
ION_HEAP(ION_IOMMU_HEAP_ID),
ION_FLAG_CACHED, sz, quiet,
pre_alloc_size,
&alloc_stats[i], &free_stats[i]);
}
print_stats_results("ION_IOC_ALLOC ION_IOMMU_HEAP_ID",
"cached", sMB,
alloc_stats, nreps);
print_stats_results("ION_IOC_FREE ION_IOMMU_HEAP_ID",
"cached", sMB,
free_stats, nreps);
for (i = 0; i < nreps; ++i) {
profile_alloc_for_heap(
ION_HEAP(ION_SYSTEM_HEAP_ID),
ION_FLAG_CACHED, sz, quiet,
pre_alloc_size,
&alloc_stats[i], &free_stats[i]);
}
print_stats_results("ION_IOC_ALLOC ION_SYSTEM_HEAP_ID",
"cached", sMB,
alloc_stats, nreps);
print_stats_results("ION_IOC_FREE ION_SYSTEM_HEAP_ID",
"cached", sMB,
free_stats, nreps);
for (i = 0; i < nreps; ++i) {
profile_alloc_for_heap(
ION_HEAP(ION_SYSTEM_HEAP_ID),
0, sz, quiet,
pre_alloc_size,
&alloc_stats[i], &free_stats[i]);
}
print_stats_results("ION_IOC_ALLOC ION_SYSTEM_HEAP_ID",
"uncached", sMB,
alloc_stats, nreps);
print_stats_results("ION_IOC_FREE ION_SYSTEM_HEAP_ID",
"uncached", sMB,
free_stats, nreps);
}
}
static void oom_test(void)
{
int rc, ionfd, cnt = 0;
struct ion_allocation_data alloc_data = {
.len = SZ_8M,
.heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID),
.flags = 0,
};
LIST_HEAD(handle_list, ion_handle_node) head;
struct handle_list *headp;
struct ion_handle_node {
struct ion_handle *handle;
LIST_ENTRY(ion_handle_node) nodes;
} *np;
LIST_INIT(&head);
ionfd = open(ION_DEV, O_RDONLY);
if (ionfd < 0) {
perror("couldn't open " ION_DEV);
return;
}
for (;; cnt++) {
rc = ioctl(ionfd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
/* game over! */
break;
} else {
np = malloc(sizeof(struct ion_handle_node));
np->handle = alloc_data.handle;
LIST_INSERT_HEAD(&head, np, nodes);
}
printf("Allocated %d MB so far...\n", cnt * 8);
}
printf("Did %d 8M allocations before dying\n", cnt);
while (head.lh_first != NULL) {
np = head.lh_first;
ioctl(ionfd, ION_IOC_FREE, np->handle);
LIST_REMOVE(head.lh_first, nodes);
free(np);
}
}
static void leak_test(void)
{
int ionfd;
struct ion_fd_data fd_data;
struct ion_allocation_data alloc_data = {
.len = SZ_4K,
.heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID),
.flags = 0,
};
puts("About to leak a handle...");
fflush(stdout);
alloc_me_up_some_ion(&ionfd, &alloc_data);
fd_data.handle = alloc_data.handle;
if (ioctl(ionfd, ION_IOC_MAP, &fd_data))
perror("Couldn't ION_IOC_MAP the buffer");
close(ionfd);
puts("closed ionfd w/o free'ing handle.");
puts("If you have CONFIG_ION_LEAK_CHECK turned on in");
puts("your kernel and have already done:");
puts("echo 1 > /debug/ion/check_leaks_on_destroy");
puts("then you should have seen a warning on your");
puts("console.");
puts("We will now sleep for 5 seconds for you to check");
puts("<debugfs>/ion/check_leaked_fds");
sleep(5);
}
#define USAGE_STRING \
"Usage: %s [options]\n" \
"\n" \
"Supported options:\n" \
"\n" \
" -h Print this message and exit\n" \
" -a Do the adversarial test (same as -l)\n" \
" -b Do basic sanity tests\n" \
" -z Size (in MB) of buffer for basic sanity tests (default=1)\n" \
" -e[REPS] Do Ion heap profiling. Optionally specify number of reps\n" \
" E.g.: -e10 would do 10 reps (default=100)\n" \
" -k Do kernel alloc profiling (requires kernel module)\n" \
" -l Do leak test (leak an ion handle)\n" \
" -m Do map extra test (requires kernel module)\n" \
" -n Do the nominal test (same as -b)\n" \
" -o Do OOM test (alloc from Ion Iommu heap until OOM)\n" \
" -p MS Sleep for MS milliseconds between stuff (for debugging)\n" \
" -r Do the repeatability test\n" \
" -s Do the stress test (same as -e)\n" \
" -t MB Size (in MB) of temp buffer pre-allocated before Ion allocations (default 0 MB)\n"
static void usage(char *progname)
{
printf(USAGE_STRING, progname);
}
int main(int argc, char *argv[])
{
int rc = 0, i, opt;
unsigned long basic_sanity_size_mb = SZ_1M;
bool do_basic_sanity_tests = false;
bool do_heap_profiling = false;
bool do_kernel_alloc_profiling = false;
bool do_map_extra_test = false;
bool do_oom_test = false;
bool do_leak_test = false;
int num_reps = 1;
int num_heap_prof_reps = NUM_REPS_FOR_HEAP_PROFILING;
int ion_pre_alloc_size = ION_PRE_ALLOC_SIZE_DEFAULT;
while (-1 != (opt = getopt(argc, argv, "abe::hklmnop:rs::t:z:"))) {
switch (opt) {
case 't':
ion_pre_alloc_size = atoi(optarg);
break;
case 'n':
case 'b':
do_basic_sanity_tests = true;
break;
case 's':
case 'e':
if (optarg)
num_heap_prof_reps = atoi(optarg);
do_heap_profiling = true;
break;
case 'k':
do_kernel_alloc_profiling = true;
break;
case 'a':
case 'l':
do_leak_test = true;
break;
case 'm':
do_map_extra_test = true;
break;
case 'o':
do_oom_test = true;
break;
case 'r':
num_reps = NUM_REPS_FOR_REPEATABILITY;
break;
case 'p':
/* ms to us */
sleepiness = atoi(optarg) * 1000;
break;
case 'z':
basic_sanity_size_mb = atoi(optarg) * SZ_1M;
break;
case 'h':
default:
usage(basename(argv[0]));
exit(1);
}
}
if (do_basic_sanity_tests)
for (i = 0; i < num_reps; ++i)
basic_sanity_tests(basic_sanity_size_mb);
if (do_map_extra_test)
for (i = 0; i < num_reps; ++i)
map_extra_test();
if (do_heap_profiling)
for (i = 0; i < num_reps; ++i)
heap_profiling(ion_pre_alloc_size,
num_heap_prof_reps);
if (do_kernel_alloc_profiling)
for (i = 0; i < num_reps; ++i)
profile_kernel_alloc();
if (do_oom_test)
for (i = 0; i < num_reps; ++i)
oom_test();
if (do_leak_test)
for (i = 0; i < num_reps; ++i)
leak_test();
return rc;
}
@@ -0,0 +1,73 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cd $(dirname $0 2>/dev/null || echo "/data/kernel-tests")
chmod 755 memory_prof
maybe_make_node()
{
thedev=$1
themisc=$2
[ -e $thedev ] || \
mknod $thedev c $(cut -d: -f1 $themisc) $(cut -d: -f2 $themisc)
}
if [ -d /system/lib/modules/ ]; then
modpath=/system/lib/modules
else
modpath=/kernel-tests/modules/lib/modules/$(uname -r)/extra
fi
memory_prof_mod=${modpath}/the_memory_prof_module.ko
memory_prof_dev=/dev/memory_prof
memory_prof_dev_sys=/sys/class/memory_prof/memory_prof/dev
ion_dev=/dev/ion
ion_dev_misc=/sys/class/misc/ion/dev
# create ion device if it doesn't exist
maybe_make_node $ion_dev $ion_dev_misc
# insert memory_prof_mod if needed
if [ ! -e $memory_prof_dev_sys ]; then
insmod $memory_prof_mod
if [ $? -ne 0 ]; then
echo "ERROR: failed to load module $memory_prof_mod"
exit 1
fi
fi
# create memory prof device if it doesn't exist
maybe_make_node $memory_prof_dev $memory_prof_dev_sys
./memory_prof $@
rmmod the_memory_prof_module
@@ -0,0 +1,338 @@
/* Copyright (c) 2013, The Linux Foundation. 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 and
* only 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <asm/cacheflush.h>
#include <asm-generic/sizes.h>
#include <mach/iommu_domains.h>
#include <linux/msm_ion.h>
#include <asm/uaccess.h>
#include "memory_prof_module.h"
#include "timing_debug.h"
#define MEMORY_PROF_DEV_NAME "memory_prof"
struct memory_prof_module_data {
struct ion_client *client;
};
static struct class *memory_prof_class;
static int memory_prof_major;
static struct device *memory_prof_dev;
static void zero_the_pages_plz(struct page **pages, int npages,
unsigned int page_size)
{
void *ptr;
int len = npages * page_size;
ptr = vmap(pages, npages, VM_IOREMAP, pgprot_writecombine(PAGE_KERNEL));
if (ptr == NULL) {
WARN(1, "BOGUS vmap ERROR!!!\n");
} else {
memset(ptr, 0, len);
dmac_flush_range(ptr, ptr + len);
vunmap(ptr);
}
}
static void test_kernel_alloc(const char *tag, gfp_t thegfp,
unsigned int page_size,
void (*transform_page)(struct page *),
void (*transform_pages)(struct page **, int, unsigned int))
{
char st1[200];
char st2[200];
int i, j;
int order = get_order(page_size);
int size = (SZ_1M * 20);
int npages = PAGE_ALIGN(size) / page_size;
struct page **pages;
pages = kmalloc(npages * sizeof(struct page *),
GFP_KERNEL);
snprintf(st1, 200, "before %s%s", tag,
transform_page ? " (flush each)" : "");
snprintf(st2, 200, "after %s%s", tag,
transform_page ? " (flush each)" : "");
timing_debug_tick(st1);
for (i = 0; i < npages; ++i) {
pages[i] = alloc_pages(thegfp, order);
if (!pages[i]) {
WARN(1, "BOGUS alloc_pages ERROR!!!\n");
npages = i;
goto out;
}
if (transform_page)
for (j = 0; j < order; j++)
transform_page(nth_page(pages[i], j));
}
timing_debug_tock(st2);
if (transform_pages) {
timing_debug_tick("before transform_pages");
transform_pages(pages, npages, page_size);
timing_debug_tock("after transform_pages");
}
out:
for (i = 0; i < npages; ++i)
__free_pages(pages[i], order);
kfree(pages);
}
#define DO_TEST_KERNEL_ALLOC(thegfp, sz, transform_page, transform_pages) \
test_kernel_alloc(#thegfp " " #sz, thegfp, sz, \
transform_page, transform_pages)
static void test_kernel_allocs(void)
{
int i;
timing_debug_init();
timing_debug_start_new_timings();
pr_err("Testing small pages without flushing individual pages\n");
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
PAGE_SIZE, NULL, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL | __GFP_HIGHMEM,
PAGE_SIZE, NULL, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL | __GFP_HIGHMEM,
PAGE_SIZE, NULL, zero_the_pages_plz);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL | __GFP_ZERO,
PAGE_SIZE, NULL, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL,
PAGE_SIZE, NULL, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL,
PAGE_SIZE, NULL, zero_the_pages_plz);
pr_err("Testing small pages with flushing individual pages\n");
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
PAGE_SIZE, flush_dcache_page, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL | __GFP_HIGHMEM,
PAGE_SIZE, flush_dcache_page, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL | __GFP_HIGHMEM,
PAGE_SIZE, flush_dcache_page,
zero_the_pages_plz);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL | __GFP_ZERO,
PAGE_SIZE, flush_dcache_page, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL,
PAGE_SIZE, flush_dcache_page, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(GFP_KERNEL,
PAGE_SIZE, flush_dcache_page,
zero_the_pages_plz);
pr_err("Testing with large page sizes without flushing individual pages\n");
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(
GFP_KERNEL | __GFP_HIGHMEM | __GFP_COMP | __GFP_ZERO,
SZ_64K, NULL, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(
GFP_KERNEL | __GFP_HIGHMEM | __GFP_COMP,
SZ_64K, NULL, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(
GFP_KERNEL | __GFP_COMP | __GFP_ZERO,
SZ_64K, NULL, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(
GFP_KERNEL | __GFP_COMP,
SZ_64K, NULL, NULL);
pr_err("Testing with large page sizes with flushing individual pages\n");
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(
GFP_KERNEL | __GFP_HIGHMEM | __GFP_COMP | __GFP_ZERO,
SZ_64K, flush_dcache_page, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(
GFP_KERNEL | __GFP_HIGHMEM | __GFP_COMP,
SZ_64K, flush_dcache_page, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(
GFP_KERNEL | __GFP_COMP | __GFP_ZERO,
SZ_64K, flush_dcache_page, NULL);
for (i = 0; i < 7; ++i)
DO_TEST_KERNEL_ALLOC(
GFP_KERNEL | __GFP_COMP,
SZ_64K, flush_dcache_page, NULL);
timing_debug_dump_results();
}
static long memory_prof_test_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
int ret = 0;
struct memory_prof_module_data *module_data = file->private_data;
switch (cmd) {
case MEMORY_PROF_IOC_CLIENT_CREATE:
{
module_data->client = msm_ion_client_create(~0, "memory_prof_module");
if (IS_ERR_OR_NULL(module_data->client))
return -EIO;
break;
}
case MEMORY_PROF_IOC_CLIENT_DESTROY:
{
ion_client_destroy(module_data->client);
break;
}
case MEMORY_PROF_IOC_TEST_MAP_EXTRA:
{
struct memory_prof_map_extra_args args;
struct ion_handle *handle;
struct ion_client *client = module_data->client;
unsigned long iova, buffer_size;
if (copy_from_user(&args, (void __user *)arg,
sizeof(struct memory_prof_map_extra_args)))
return -EFAULT;
handle = ion_import_dma_buf(client, args.ionfd);
if (IS_ERR_OR_NULL(handle)) {
pr_err("Couldn't do ion_import_dma_buf in "
"MEMORY_PROF_IOC_TEST_MAP_EXTRA\n");
return -EINVAL;
}
ret = ion_map_iommu(client, handle, VIDEO_DOMAIN,
VIDEO_FIRMWARE_POOL, SZ_8K,
args.iommu_map_len, &iova, &buffer_size,
0, 0);
if (ret) {
pr_err("Couldn't ion_map_iommu in "
"MEMORY_PROF_IOC_TEST_MAP_EXTRA\n");
return ret;
}
break;
}
case MEMORY_PROF_IOC_TEST_KERNEL_ALLOCS:
{
test_kernel_allocs();
break;
}
default:
pr_info("command not supproted\n");
ret = -EINVAL;
}
return ret;
}
static int memory_prof_test_open(struct inode *inode, struct file *file)
{
struct memory_prof_module_data *module_data = kzalloc(
sizeof(struct memory_prof_module_data), GFP_KERNEL);
if (!module_data)
return -ENOMEM;
file->private_data = module_data;
pr_info("memory_prof test device opened\n");
return 0;
}
static int memory_prof_test_release(struct inode *inode, struct file *file)
{
struct memory_prof_module_data *module_data = file->private_data;
kfree(module_data);
pr_info("memory_prof test device closed\n");
return 0;
}
static const struct file_operations memory_prof_test_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = memory_prof_test_ioctl,
.open = memory_prof_test_open,
.release = memory_prof_test_release,
};
static int memory_prof_device_create(void)
{
int rc = 0;
memory_prof_major = register_chrdev(0, MEMORY_PROF_DEV_NAME,
&memory_prof_test_fops);
if (memory_prof_major < 0) {
rc = memory_prof_major;
pr_err("Unable to register chrdev: %d\n", memory_prof_major);
goto out;
}
memory_prof_class = class_create(THIS_MODULE, MEMORY_PROF_DEV_NAME);
if (IS_ERR(memory_prof_class)) {
rc = PTR_ERR(memory_prof_class);
pr_err("Unable to create class: %d\n", rc);
goto err_create_class;
}
memory_prof_dev = device_create(memory_prof_class, NULL,
MKDEV(memory_prof_major, 0),
NULL, MEMORY_PROF_DEV_NAME);
if (IS_ERR(memory_prof_dev)) {
rc = PTR_ERR(memory_prof_dev);
pr_err("Unable to create device: %d\n", rc);
goto err_create_device;
}
return rc;
err_create_device:
class_destroy(memory_prof_class);
err_create_class:
unregister_chrdev(memory_prof_major, MEMORY_PROF_DEV_NAME);
out:
return rc;
}
static void memory_prof_device_destroy(void)
{
device_destroy(memory_prof_class, MKDEV(memory_prof_major, 0));
class_destroy(memory_prof_class);
unregister_chrdev(memory_prof_major, MEMORY_PROF_DEV_NAME);
}
static int memory_prof_test_init(void)
{
return memory_prof_device_create();
}
static void memory_prof_test_exit(void)
{
return memory_prof_device_destroy();
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Profile memory stuff");
module_init(memory_prof_test_init);
module_exit(memory_prof_test_exit);
@@ -0,0 +1,32 @@
/* Copyright (c) 2013, The Linux Foundation. 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 and
* only 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.
*/
#ifndef _MEMORY_PROF_MODULE_H
#include <linux/ioctl.h>
struct memory_prof_map_extra_args {
int ionfd;
unsigned long iommu_map_len;
};
#define MEMORY_PROF_MAGIC 'H'
#define MEMORY_PROF_IOC_CLIENT_CREATE _IO(MEMORY_PROF_MAGIC, 0)
#define MEMORY_PROF_IOC_CLIENT_DESTROY _IO(MEMORY_PROF_MAGIC, 1)
#define MEMORY_PROF_IOC_TEST_MAP_EXTRA \
_IOR(MEMORY_PROF_MAGIC, 2, struct memory_prof_map_extra_args)
#define MEMORY_PROF_IOC_TEST_KERNEL_ALLOCS _IO(MEMORY_PROF_MAGIC, 3)
#endif /* #ifndef _MEMORY_PROF_MODULE_H */
@@ -0,0 +1,256 @@
#!/usr/bin/env python
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Quick and very dirty parser for the output of `memory_prof.sh -e'
# This should be run on the host (not the target) with the output from
# the target piped in (e.g. copy/paste/cat) or passed as a file on the
# command line
# Dependencies: matplotlib, numpy
# NOTE: THIS HAS GOTTEN UNWIELDY. YOU HAVE BEEN WARNED.
import sys
import fileinput
import operator
from itertools import cycle
from optparse import OptionParser
import numpy as np
import matplotlib.pyplot as plt
ST_PREFIX_DATA_ROW = "=> "
ST_PREFIX_PREALLOC_SIZE = "==> "
ST_PREFIX_NUM_REPS = "===> "
def get_data_lines(data):
return [line.lstrip(ST_PREFIX_DATA_ROW).rstrip('\n') for line in data if line.startswith(ST_PREFIX_DATA_ROW)]
def extract_data_for_size(data, target_sz):
cached_timings = {
'ION_IOC_ALLOC': [],
'ION_IOC_FREE': [],
}
uncached_timings = {
'ION_IOC_ALLOC': [],
'ION_IOC_FREE': [],
}
heaps = []
for line in get_data_lines(data):
# for the format, see print_stats_results in memory_prof.c
(ion_op, heap_id, caching, sz, lbl_av, average, lbl_std, std_dev) = line.split(' ')
if sz != target_sz: continue
av = max(float(average), 0)
if heap_id not in heaps:
heaps.append(heap_id)
if caching == 'cached':
cached_timings[ion_op].append(av)
else:
uncached_timings[ion_op].append(av)
return (heaps, cached_timings, uncached_timings)
def extract_all_data(data):
timings = {
'ION_IOC_ALLOC': {},
'ION_IOC_FREE': {},
}
for line in get_data_lines(data):
# for the format, see print_stats_results in memory_prof.c
(ion_op, heap_id, caching, sz, lbl_av, average, lbl_std, std_dev) = line.split(' ')
timings[ion_op].setdefault(heap_id, {})
av = max(float(average), 0)
timings[ion_op][heap_id].setdefault(caching, {})
timings[ion_op][heap_id][caching][sz] = float(average)
return timings
def compare_heaps_for_a_size(data, target_sz, num_reps, pre_alloc_size, ion_op, text_only=False, target=None):
(heaps, cached_timings, uncached_timings) = extract_data_for_size(data, target_sz)
cached_timings = cached_timings[ion_op]
uncached_timings = uncached_timings[ion_op]
title = ('Ion %s times\n' % ion_op) \
+ ('Target: %s' % ("%s\n" % target) if target is not None else "") \
+ ('(%s with ION_IOC_ALLOC, average of %d reps, %dMB pre-allocation)' % (target_sz, num_reps, pre_alloc_size))
print title
print
for (heap, cached, uncached) in zip(heaps, cached_timings, uncached_timings):
print "%25s (cached): %f" % (heap, cached)
print "%25s (uncached): %s" % (heap, str(uncached) if uncached != 0 else "N/A")
if text_only:
return
ind = np.arange(len(heaps))
width = .35
fig = plt.figure()
ax = fig.add_subplot(111)
cached_rects = ax.bar(ind, cached_timings, width, color='r')
uncached_rects = ax.bar(ind + width, uncached_timings, width, color='y')
ax.set_title(title)
ax.set_ylabel('Time (ms)')
ax.set_xticks(ind + width)
ax.set_xticklabels(heaps)
ax.legend( (cached_rects[0], uncached_rects[0]), ('Cached', 'Uncached') )
plt.show()
def first_key_element(d):
"Returns the first element found in the dict `d'."
return d[d.keys()[0]]
def compare_times_for_heaps(data, num_reps, pre_alloc_size, ion_op, text_only=False, target=None):
timings = extract_all_data(data)[ion_op]
# we need to sort the size strings, which are a few levels in
# (through some keys that might or might not exist)
first_heap_timing = first_key_element(timings)
sizes_for_heap_timing = first_key_element(first_heap_timing)
sorted_keys = sorted(
sizes_for_heap_timing.keys(),
key=lambda v: float(v.split('MB')[0])
)
for target_heap in timings.keys():
heap_timings = timings[target_heap]
print '%s times for %s (%d reps, %dMB pre-allocation)\n' \
% (ion_op, target_heap, num_reps, pre_alloc_size)
format_str = '%6s %10s %10s'
print format_str % (
'Size', 'Cached', 'Uncached',
)
for k in sorted_keys:
print format_str % (
k,
('%5.2f' % heap_timings['cached'][k]) if 'cached' in heap_timings else 'NA',
('%5.2f' % heap_timings['uncached'][k]) if 'uncached' in heap_timings else 'NA',
)
print '\n'
if text_only:
return
fig = plt.figure()
ax = fig.add_subplot(111)
sorted_keys_numbers = [float(s.split('MB')[0]) for s in sorted_keys]
shapes_cycler = cycle(["o", "v", "^" , "<", ">"])
for target_heap in timings.keys():
for caching in ('cached', 'uncached'):
heap_timings = timings[target_heap]
if caching in heap_timings:
lbl = "%s (%s)" % (target_heap, caching)
ax.plot(sorted_keys_numbers,
[heap_timings[caching][k] for k in sorted_keys],
next(shapes_cycler) + '-',
label=lbl)
title = ("Ion %s times\n" % ion_op) \
+ ('%s' % ("Target: %s\n" % target) if target is not None else "") \
+ ("(average of %d reps)" % num_reps)
ax.set_ylabel("Time (ms)")
ax.set_xlabel("Allocation size (MB)")
ax.set_title(title)
ax.legend(loc="upper left")
plt.grid(True)
plt.show()
if __name__ == "__main__":
target_sz = None
parser = OptionParser()
parser.add_option("-c", "--compare-heaps", action="store_true",
help="Compare same-sized allocations across heaps")
parser.add_option("-z", "--compare-alloc-sizes", action="store_true",
help="Compare same-heap allocations across sizes")
parser.add_option("-s", "--size", metavar="SIZE",
help="Allocation size to plot (e.g. '8MB'). Only used with -c")
# parser.add_option("-e", "--heap", metavar="HEAP",
# help="Heap to plot (e.g. 'ION_CP_MM_HEAP_ID'), or 'ALL'. Only used with -z")
parser.add_option("-t", "--text-only", action="store_true")
parser.add_option("--target", help="Name of the device (used for plot titles)")
parser.add_option("-o", "--ion-op",
default="ION_IOC_ALLOC",
help="Ion operation to display (currently supported: ION_IOC_ALLOC, ION_IOC_FREE)")
(options, args) = parser.parse_args()
if options.compare_heaps and not options.size:
print "You must provide a size (-s) when comparing same-sized allocations across heaps (-c)"
sys.exit(1)
if not options.compare_heaps and not options.compare_alloc_sizes:
print "You must specify either -c or -z"
sys.exit(1)
# snarf:
data = [line for line in fileinput.input(args)]
# get the num reps:
repsline = [line for line in data if line.startswith(ST_PREFIX_NUM_REPS)][0]
num_reps = int(repsline.split(' ')[-1])
# get the pre-alloc size:
prealloclines = [line for line in data if line.startswith(ST_PREFIX_PREALLOC_SIZE)]
if len(prealloclines) > 0:
pre_alloc_size = int(prealloclines[0].split(' ')[-1])
else:
pre_alloc_size = 0
if options.compare_heaps:
compare_heaps_for_a_size(data, options.size, num_reps,
pre_alloc_size,
options.ion_op,
text_only=options.text_only,
target=options.target)
if options.compare_alloc_sizes:
compare_times_for_heaps(data, num_reps,
pre_alloc_size,
options.ion_op,
text_only=options.text_only,
target=options.target)
@@ -0,0 +1,39 @@
#!/bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cd $(dirname $0)
echo ":: Doing a basic sanity test"
./memory_prof.sh -b
echo ":: Doing Ion profiling"
./memory_prof.sh -e
echo ":: Doing kernel alloc profiling"
./memory_prof.sh -k
@@ -0,0 +1,115 @@
/* Copyright (c) 2013, The Linux Foundation. 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 and
* only 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.
*/
/**
* file: timing_debug.c
*
* A simple nesting timer module.
*
* IMPORTANT: THIS IS NOT THREAD SAFE!
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include "timing_debug.h"
#define MODULE_NAME "TIMING_DEBUG"
#define __TIMING_DEBUG_TIME_MAX_CLOCK_NESTING 100
#define __TIMING_DEBUG_TIME_MAX_TICKS_AND_TOCKS_PER_SESSION 5000
#define __TIMING_DEBUG_TIME_LINE_SIZE 100
static struct timespec __timing_debug_t1[__TIMING_DEBUG_TIME_MAX_CLOCK_NESTING];
static struct timespec __timing_debug_t2[__TIMING_DEBUG_TIME_MAX_CLOCK_NESTING];
static int __timing_debug_time_sp;
static int __timing_debug_time_timing_buf_cur;
static char *__timing_debug_timing_message_buffer[
__TIMING_DEBUG_TIME_MAX_TICKS_AND_TOCKS_PER_SESSION];
void timing_debug_start_new_timings(void)
{
__timing_debug_time_timing_buf_cur = 0;
}
void timing_debug_dump_results(void)
{
int i;
for (i = 0; i < __timing_debug_time_timing_buf_cur; ++i)
pr_err("[timing debug] %s",
__timing_debug_timing_message_buffer[i]);
}
static char *__timing_debug_get_spaces(void)
{
int i;
static char spaces[__TIMING_DEBUG_TIME_MAX_CLOCK_NESTING];
char *it = spaces;
for (i = 0; i < __timing_debug_time_sp; ++i)
*it++ = ' ';
*it++ = '\0';
return spaces;
}
void timing_debug_tick(char *msg)
{
snprintf(__timing_debug_timing_message_buffer[
__timing_debug_time_timing_buf_cur++],
__TIMING_DEBUG_TIME_LINE_SIZE,
"%stick %s\n", __timing_debug_get_spaces(), msg);
getnstimeofday(&__timing_debug_t1[__timing_debug_time_sp]);
__timing_debug_time_sp++;
}
void timing_debug_tock(char *msg)
{
struct timespec diff;
--__timing_debug_time_sp;
getnstimeofday(&__timing_debug_t2[__timing_debug_time_sp]);
diff = timespec_sub(__timing_debug_t2[__timing_debug_time_sp],
__timing_debug_t1[__timing_debug_time_sp]);
snprintf(__timing_debug_timing_message_buffer[
__timing_debug_time_timing_buf_cur++],
__TIMING_DEBUG_TIME_LINE_SIZE,
"%stock %s => Delta: %ld ms\n",
__timing_debug_get_spaces(), msg,
(long int) div_s64(timespec_to_ns(&diff), 1000000));
}
/* TODO: protect with a mutex */
static bool did_init;
int timing_debug_init(void)
{
int i, rc = 0;
if (did_init)
return 0;
for (i = 0;
i < __TIMING_DEBUG_TIME_MAX_TICKS_AND_TOCKS_PER_SESSION;
++i) {
void *buf = kmalloc(__TIMING_DEBUG_TIME_LINE_SIZE, GFP_KERNEL);
if(!buf) {
rc = -ENOMEM;
goto out;
}
__timing_debug_timing_message_buffer[i] = buf;
}
did_init = true;
out:
return rc;
}
@@ -0,0 +1,41 @@
/* Copyright (c) 2013, The Linux Foundation. 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 and
* only 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.
*/
#ifndef _TIMING_DEBUG_H
/**
* Init the timings system
*/
int timing_debug_init(void);
/**
* Start a new set of timings
*/
void timing_debug_start_new_timings(void);
/**
* Dump results from current set of timings.
*/
void timing_debug_dump_results(void);
/**
* Record tick.
*/
void timing_debug_tick(char *msg);
/**
* Record tock. timing_debug_dump_results will then show the difference
* between this tock and the last tick.
*/
void timing_debug_tock(char *msg);
#endif /* #ifndef _TIMING_DEBUG_H */
@@ -0,0 +1,32 @@
BOARD_PLATFORM_LIST := msm8660
BOARD_PLATFORM_LIST += msm8960
BOARD_PLATFORM_LIST += apq8064
BOARD_PLATFORM_LIST += msm8930
BOARD_PLATFORM_LIST += msm8974
BOARD_PLATFORM_LIST += mdm9625
BOARD_PLATFORM_LIST += msm8226
BOARD_PLATFORM_LIST += msm8610
ifeq ($(call is-board-platform-in-list, $(BOARD_PLATFORM_LIST)),true)
DLKM_DIR := device/qcom/common/dlkm
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_COPY_HEADERS_TO := kernel-tests/msm_bus
LOCAL_COPY_HEADERS := msm_bus_test.h
include $(BUILD_COPY_HEADERS)
LOCAL_MODULE := msm_bus_ioctl.ko
LOCAL_MODULE_TAGS := eng
include $(DLKM_DIR)/AndroidKernelModule.mk
include $(CLEAR_VARS)
LOCAL_MODULE := msm_bus_test
LOCAL_SRC_FILES := msm_bus_test.c
LOCAL_C_FLAGS := -lpthread
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests
include $(BUILD_EXECUTABLE)
endif
@@ -0,0 +1 @@
obj-m := msm_bus_ioctl.o
@@ -0,0 +1,24 @@
KERNEL_FLAGS ?= ARCH=arm
module = msm_bus_ioctl.ko
kmake = $(MAKE) $(KERNEL_FLAGS) -C $(KERNEL_DIR) M=$(CURDIR)
$(module):
$(kmake) modules
all-local: $(module)
install-exec-local: $(module)
$(kmake) INSTALL_MOD_PATH=$(DESTDIR)$(prefix)/modules modules_install
# "make distclean" will always run clean-local in this directory,
# regardless of the KERNELMODULES conditional. Therefore, ensure
# KERNEL_DIR exists before running clean. Further, don't fail even
# if there is a problem.
clean-local:
-test ! -d "$(KERNEL_DIR)" || $(kmake) clean
msm_busdir = $(prefix)/msm_bus
include_HEADERS = msm_bus_test.h
@@ -0,0 +1,202 @@
/* Copyright (c) 2012, The Linux Foundation. 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 and
* only 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.
*/
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#include "msm_bus_test.h"
static int msm_bus_create_client(unsigned long arg)
{
struct msm_bus_paths *usecase;
struct msm_bus_vectors *vectors;
struct msm_bus_scale_pdata *pdata;
int i, j;
struct msm_bus_test_cldata cldata;
uint32_t clid;
pdata = kmalloc(sizeof(struct msm_bus_scale_pdata), GFP_KERNEL);
pr_debug("AXI: %s(): create cl\n", __func__);
if (__copy_from_user(&cldata, (void __user *)arg,
sizeof(struct msm_bus_test_cldata))) {
pr_err("AXI: %s(): Error getting user memory\n", __func__);
return -EFAULT;
}
pdata->name = cldata.pdata.name;
pdata->active_only = cldata.pdata.active_only;
pdata->num_usecases = cldata.pdata.num_usecases;
usecase = kmalloc(((pdata->num_usecases) *
sizeof(struct msm_bus_paths)), GFP_KERNEL);
if (IS_ERR(usecase)) {
pr_err("AXI: %s(): Error creating usecase in test\n", __func__);
return -ENOMEM;
}
pdata->usecase = usecase;
for (i = 0; i < pdata->num_usecases; i++) {
pdata->usecase[i].num_paths = cldata.pdata.usecase[i].num_paths;
vectors = kmalloc((pdata->usecase[i].num_paths *
sizeof(struct msm_bus_vectors)), GFP_KERNEL);
if (IS_ERR(vectors)) {
for (j = 0; j < i; j++)
kfree(pdata->usecase[j].vectors);
kfree(pdata->usecase);
kfree(pdata);
pr_err("AXI: %s(): Error creating usecase in test\n",
__func__);
return -ENOMEM;
}
for (j = 0; j < pdata->usecase[i].num_paths; j++) {
vectors[j].src = cldata.pdata.usecase[i].vectors[j].src;
vectors[j].dst = cldata.pdata.usecase[i].vectors[j].dst;
vectors[j].ab = cldata.pdata.usecase[i].vectors[j].ab;
vectors[j].ib = cldata.pdata.usecase[i].vectors[j].ib;
}
pdata->usecase[i].vectors = vectors;
}
clid = msm_bus_scale_register_client(pdata);
pr_debug("AXI: %s(): Got client id: %u\n", __func__, clid);
cldata.clid = clid;
cldata.pdatah = (uint32_t)(pdata);
if (__copy_to_user((void __user *)arg, &cldata,
sizeof(struct msm_bus_test_cldata))) {
pr_err("AXI: %s(): Error copying data to client\n", __func__);
msm_bus_scale_unregister_client(clid);
for (i = 0; i < pdata->num_usecases; i++)
kfree(pdata->usecase[i].vectors);
kfree(pdata->usecase);
kfree(pdata);
return -EFAULT;
}
return 0;
}
static int msm_bus_ioctl_unreg_cl(unsigned cmd, unsigned long arg)
{
int retval = 0, i;
uint32_t clid;
struct msm_bus_test_cldata cldata;
struct msm_bus_scale_pdata *pdata;
if (__copy_from_user(&cldata, (void __user *)arg,
sizeof(struct msm_bus_test_cldata)))
retval = -EFAULT;
clid = cldata.clid;
pr_debug("AXI: %s(): IOCTL: Unregister cl%u\n", __func__, clid);
msm_bus_scale_unregister_client(clid);
pdata = (struct msm_bus_scale_pdata *)cldata.pdatah;
for (i = 0; i < pdata->num_usecases; i++)
kfree(pdata->usecase[i].vectors);
kfree(pdata->usecase);
kfree(pdata);
return retval;
}
static int msm_bus_ioctl_update_req(unsigned cmd, unsigned long arg)
{
int retval = 0;
struct msm_bus_test_update_req_data rdata;
if (__copy_from_user(&rdata, (void __user *)arg,
sizeof(rdata))) {
retval = -EFAULT;
goto err;
}
pr_debug("AXI: %s(): IOCTL: Update req for cl: %u, index: %d\n",
__func__, rdata.clid, rdata.index);
retval = msm_bus_scale_client_update_request(rdata.clid,
rdata.index);
err:
return retval;
}
static long msm_bus_test_ioctl(struct file *file, unsigned cmd,
unsigned long arg)
{
long retval = 0;
pr_debug("AXI: %s(): entering test ioctl\n", __func__);
if (_IOC_TYPE(cmd) != MSM_BUS_TEST_IOC_MAGIC) {
pr_err("AXI: %s(): Wrong IOC_MAGIC.Exiting\n", __func__);
return -ENOTTY;
}
switch (cmd) {
case MSM_BUS_TEST_REG_CL:
retval = msm_bus_create_client(arg);
break;
case MSM_BUS_TEST_UNREG_CL:
retval = msm_bus_ioctl_unreg_cl(cmd, arg);
break;
case MSM_BUS_TEST_UPDATE_REQ:
retval = msm_bus_ioctl_update_req(cmd, arg);
break;
default:
pr_err("AXI: %s(): IOCTL: Invalid case\n", __func__);
retval = -EFAULT;
break;
}
return retval;
}
static const struct file_operations msm_bus_test_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = msm_bus_test_ioctl,
};
static struct miscdevice msm_bus_test_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "msmbustest",
.fops = &msm_bus_test_fops,
};
static int msm_bus_test_init(void)
{
int ret;
pr_debug("AXI: %s(): Initializing ioctl module\n", __func__);
ret = misc_register(&msm_bus_test_dev);
if (ret < 0)
return ret;
return 0;
}
static void msm_bus_test_exit(void)
{
pr_debug("AXI: %s(): Exiting ioctl module\n", __func__);
misc_deregister(&msm_bus_test_dev);
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Test for MSM Bus Scaling driver");
MODULE_VERSION("1.00");
module_init(msm_bus_test_init);
module_exit(msm_bus_test_exit);
@@ -0,0 +1,405 @@
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include "msm_bus_test.h"
#define MBPS(n) ((n) * 1000000)
#define NUM_ITERATIONS 1000
#define NUM_STRESS_ITERATIONS 20000
#define MAX_NUM_THREADS 20
static unsigned int iter;
static unsigned int nthreads;
void configureclient(struct msm_bus_test_scale_pdata *pdata, int target)
{
int i, j;
for (i = 0; i < NUM_USECASES; i++) {
for (j = 0; j < NUM_VECTORS; j++) {
pdata->usecase[i].vectors[j].dst =
MSM_BUS_TEST_SLAVE_FIRST;
pdata->usecase[i].vectors[j].ab = 0;
pdata->usecase[i].vectors[j].ib = MBPS(j);
}
pdata->usecase[i].num_paths = NUM_VECTORS;
}
if (target == 8960 || target == 8660 || target == 9615 ||
target == 8064 || target == 8930 || target == 'A' ||
target == 'a') {
for (i = 0; i < NUM_USECASES; i++) {
pdata->usecase[i].vectors[0].src =
MSM_BUS_TEST_MASTER_AMPSS_M0;
pdata->usecase[i].vectors[1].src =
MSM_BUS_TEST_MASTER_SPS;
pdata->usecase[i].vectors[2].src =
MSM_BUS_TEST_MASTER_LPASS;
pdata->usecase[i].vectors[3].src =
MSM_BUS_TEST_MASTER_ADM0_PORT0;
pdata->usecase[i].vectors[4].src =
MSM_BUS_TEST_MASTER_ADM0_PORT1;
}
} else if (target == 8974 || target == 9625 || target == 8226
|| target == 8610 || target == 'B' ||
target == 'b' || target == 8084) {
for (i = 0; i < NUM_USECASES; i++) {
pdata->usecase[i].vectors[0].src =
MSM_BUS_TEST_MASTER_AMPSS_M0;
pdata->usecase[i].vectors[1].src =
MSM_BUS_TEST_MASTER_LPASS_PROC;
pdata->usecase[i].vectors[2].src =
MSM_BUS_TEST_MASTER_CRYPTO_CORE0;
pdata->usecase[i].vectors[3].src =
MSM_BUS_TEST_MASTER_SDCC_1;
pdata->usecase[i].vectors[4].src =
MSM_BUS_TEST_MASTER_QDSS_BAM;
}
} else {
printf("Warning! Couldn't configure client. Target ID %d"
" is not valid. Tests may fail\n"
"Please provide a valid target-id. See usage\n",
target);
}
printf("%s\n", "TestClient");
pdata->active_only = 0;
pdata->num_usecases = NUM_USECASES;
pdata->name = "TestClient";
}
static void print_usage()
{
printf("Usage:\n");
puts(" Supported targets: 8660, 8960, 8930, 9615, 8064, 8974, 9625, "
"8226, 8610, 8084\n"
"Supported families: A & B\n"
"Usage with shell script:\n"
"\tWith target IDs:\n"
"--target <target-id ex. 8974> --nominal\n"
" Nominal is set by default\n"
" Example: ./msm_bus_test.sh --nominal --target 8974\n"
"--target <target-id> --adversarial\n"
" Example: ./msm_bus_test.sh --target 8226 --adversarial\n"
"--target <target-id> --stress [Number of threads]\n"
" Example: ./msm_bus_test.sh --target 9615 --stress 2\n"
"--target <target-id> --repeatability [Number of iterations]\n"
" Example: ./msm_bus_test.sh --target 8610 --repeatability 100\n"
"\nWith with families:\n"
"./msm_bus_test.sh --family A --nominal\n\n"
"Usage directly through test app\n"
"insmod /system/lib/modules/msm_bus_ioctl.ko\n"
"./msm_bus_test --target <Target-ID> --test-type <test-type args>\n"
"Example: ./msm_bus_test --target 8974 --stress 5\n"
"Example: ./msm_bus_test --family B --repeatability 100\n");
exit(1);
}
static int parse_args(int argc, char **argv, int *target)
{
struct option lopts[] = {
{ "nominal", no_argument, NULL, 'n'},
{ "adversarial", no_argument, NULL, 'a'},
{ "stress", required_argument, NULL, 's'},
{ "repeatability", required_argument, NULL, 'r'},
{ "target", required_argument, NULL, 't'},
{ "family", required_argument, NULL, 'f'},
{ NULL, 0, NULL, 0},
};
int command, target_id = 0, ret = 0;
const char *optstr = "n:a:s:r:t:f";
while ((command = getopt_long(argc, argv, optstr, lopts, NULL)) != -1) {
switch (command) {
case 'n':
printf("\nRunning nominal tests...\n");
ret = 'n';
break;
case 'r':
if (optarg) {
printf("Iterations: %d\n\n", atoi(optarg));
iter = atoi(optarg);
} else {
printf("Using default iterations\n");
iter = NUM_ITERATIONS;
}
printf("Running stress tests...\n");
ret = 'r';
break;
case 'a':
printf("Running adversarial tests...\n");
ret = 'a';
break;
case 's':
if (optarg) {
printf("number of threads: %d\n\n",
atoi(optarg));
nthreads = atoi(optarg);
} else {
printf("Using max number of threads\n");
nthreads = MAX_NUM_THREADS;
iter = NUM_ITERATIONS;
}
printf("\nRunning repeatability test for %d "
"iterations\n", iter);
ret = 's';
break;
case 't':
if (optarg) {
printf("\nGot target ID: %d\n", atoi(optarg));
target_id = atoi(optarg);
*target = target_id;
break;
}
case 'f':
if (optarg) {
printf("\nGot Family %c\n", optarg[0]);
target_id = optarg[0];
*target = target_id;
break;
}
default:
printf("\nDefault option: Running nominal tests...\n");
ret = 'n';
break;
}
}
if (target_id == 0) {
printf("\nTarget id not found. Usage:\n");
print_usage();
ret = 0;
}
return ret;
}
static int nominal(int fd, int target)
{
uint32_t clid;
int i, retval = 0;
struct msm_bus_test_update_req_data rdata;
struct msm_bus_test_cldata cldata;
configureclient(&cldata.pdata, target);
retval = ioctl(fd, MSM_BUS_TEST_REG_CL, &cldata);
clid = cldata.clid;
printf("Getting client id...\n");
if (clid != 0) {
printf("Got client id: %u\n", clid);
rdata.clid = clid;
} else {
printf("Client could not be registered\n");
goto err;
}
rdata.index = (rand() % NUM_USECASES);
printf("Updating request for cl %u, index: %d\n", clid, rdata.index);
retval = ioctl(fd, MSM_BUS_TEST_UPDATE_REQ, &rdata);
rdata.index = 0;
retval = ioctl(fd, MSM_BUS_TEST_UPDATE_REQ, &rdata);
printf("Unregistering client: %u\n", cldata.clid);
retval = ioctl(fd, MSM_BUS_TEST_UNREG_CL, &cldata);
printf("Client unregistered: %u\n", clid);
err:
return retval;
}
static int adversarial(int fd, int target)
{
struct msm_bus_test_update_req_data rdata;
struct msm_bus_test_cldata cldata;
configureclient(&cldata.pdata, target);
printf("Test 1: Using invalid master id\n");
cldata.pdata.usecase[0].vectors[0].src = MSM_BUS_TEST_SLAVE_FIRST;
ioctl(fd, MSM_BUS_TEST_REG_CL, &cldata);
printf("Getting client id...\n");
if (cldata.clid != 0) {
printf("Got client id: %u\n", cldata.clid);
rdata.clid = cldata.clid;
} else
printf("Client could not be registered: %d\n", cldata.clid);
printf("Test 2: Using invalid slave id\n");
cldata.pdata.usecase[0].vectors[0].src = MSM_BUS_TEST_MASTER_FIRST;
cldata.pdata.usecase[0].vectors[0].dst = MSM_BUS_TEST_MASTER_MDP_PORT0;
ioctl(fd, MSM_BUS_TEST_REG_CL, &cldata);
printf("Getting client id...\n");
if (cldata.clid != 0) {
printf("Got client id: %u\n", cldata.clid);
rdata.clid = cldata.clid;
} else
printf("Success. Client could not be registered: %d\n",
cldata.clid);
printf("Test 3: Using negative index\n");
cldata.pdata.usecase[0].vectors[0].src = MSM_BUS_TEST_MASTER_FIRST;
cldata.pdata.usecase[0].vectors[0].dst = MSM_BUS_TEST_SLAVE_FIRST;
ioctl(fd, MSM_BUS_TEST_REG_CL, &cldata);
printf("Getting client id...\n");
if (cldata.clid != 0) {
printf("Got client id: %u\n", cldata.clid);
rdata.clid = cldata.clid;
}
rdata.clid = cldata.clid;
rdata.index = -5;
if (ioctl(fd, MSM_BUS_TEST_UPDATE_REQ, &rdata))
printf("Success: Request couldn't be updated:\n");
printf("Test 4: Using out of bounds index\n");
rdata.clid = cldata.clid;
rdata.index = 35;
if (ioctl(fd, MSM_BUS_TEST_UPDATE_REQ, &rdata))
printf("Success: Request couldn't be updated:\n");
err:
return 0;
}
static int repeatability(int fd, int ni, int target)
{
int i, retval;
for (i = 0; i < ni; i++) {
printf("Iteration %d\n", i);
retval = nominal(fd, target);
if (retval) {
printf("\nRepeatability test failed at "
"iteration: %d\n", i);
return retval;
}
}
return 0;
}
void *rep_threadfn(void *thargs)
{
int ret = 0;
ret = repeatability(((int *)thargs)[0], ((int *)thargs)[1],
((int *)thargs)[2]);
if (ret)
printf("\nError :%d\n", ret);
return (void *)ret;
}
static int stress(int fd, int target)
{
int ret = 0;
unsigned int i, j;
pthread_t thread[MAX_NUM_THREADS];
int iret[MAX_NUM_THREADS];
int thargs[3];
printf("\nRunning stress test 1\n"
"Register client, update request with different clock values,"
"unregister client...\n");
ret = repeatability(fd, NUM_ITERATIONS, target);
if (ret)
printf("Stress test 1 failed..\n");
printf("\nRunning stress test 2\n"
"Concurrency test: Spawn 20 threads which register client, "
"upadte request, and unregister client..\n");
thargs[0] = fd;
thargs[1] = NUM_ITERATIONS;
thargs[2] = target;
for (i = 0; i < nthreads; i++) {
iret[i] = pthread_create(&thread[i], NULL, rep_threadfn,
(void *) thargs);
if (iret[i]) {
printf("\nFailed to create %d thread for stress "
"test..\n", i);
for (j = 0; j < i; j++)
pthread_join(thread[j], NULL);
printf("\nStress test failed in thread creation\n");
ret = -1;
return ret;
}
printf("\nRunning test thread %d\n", i);
}
for (i = 0; i < nthreads; i++)
pthread_join(thread[i], NULL);
return 0;
}
int main(int argc, char **argv)
{
int fd, test, target = 0;
test = parse_args(argc, argv, &target);
if (test < 0)
return 1;
printf("In main for msm_bus_test\n");
fd = open("/dev/msmbustest", O_RDWR | O_SYNC);
if (fd < 0) {
perror("Unable to open /dev/msmbustest");
exit(1);
}
printf("\nGot test :%c\n", test);
switch (test) {
case 'n':
nominal(fd, target);
break;
case 's':
stress(fd, target);
break;
case 'a':
adversarial(fd, target);
break;
case 'r':
printf("\nStarting repeatability tests:\n");
repeatability(fd, iter, target);
break;
default:
nominal(fd, target);
break;
}
close(fd);
exit(0);
}
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __MSM_BUS_TEST__
#define __MSM_BUS_TEST__
#include <linux/ioctl.h>
#define MSM_BUS_IOC_MAGIC 0x80
#define TEST_SLAVE_ID_KEY 512
#define NUM_USECASES 10
#define NUM_VECTORS 5
/**
* The test enums do not contain the gateway master/slave IDs. Hence, they
* differ from the enums used in boards file.
* This is done so that random master/slave pairs can be created for
* testing.
*/
enum msm_bus_test_fabric_master_type {
MSM_BUS_TEST_MASTER_FIRST = 1,
MSM_BUS_TEST_MASTER_AMPSS_M0 = 1,
MSM_BUS_TEST_MASTER_SPS = 6,
MSM_BUS_TEST_MASTER_ADM0_PORT0,
MSM_BUS_TEST_MASTER_ADM0_PORT1,
MSM_BUS_TEST_MASTER_LPASS_PROC = 11,
MSM_BUS_TEST_MASTER_LPASS = 15,
MSM_BUS_TEST_MASTER_MDP_PORT0 = 22,
MSM_BUS_TEST_MASTER_HD_CODEC_PORT0 = 34,
MSM_BUS_TEST_MASTER_QDSS_BAM = 53,
MSM_BUS_TEST_MASTER_CRYPTO_CORE0 = 55,
MSM_BUS_TEST_MASTER_SDCC_1 = 78,
};
enum msm_bus_test_fabric_slave_type {
MSM_BUS_TEST_SLAVE_FIRST = TEST_SLAVE_ID_KEY,
MSM_BUS_TEST_SLAVE_EBI_CH0 = TEST_SLAVE_ID_KEY,
};
struct msm_bus_test_vectors {
int src; /* Master */
int dst; /* Slave */
unsigned int ab; /* Arbitrated bandwidth */
unsigned int ib; /* Instantaneous bandwidth */
};
struct msm_bus_test_paths {
int num_paths;
struct msm_bus_test_vectors vectors[NUM_VECTORS];
};
struct msm_bus_test_scale_pdata {
struct msm_bus_test_paths usecase[NUM_USECASES];
int num_usecases;
const char *name;
unsigned int active_only;
};
struct msm_bus_test_cldata {
struct msm_bus_test_scale_pdata pdata;
uint32_t clid;
uint32_t pdatah;
};
struct msm_bus_test_update_req_data {
uint32_t clid;
uint32_t index;
};
#define MSM_BUS_TEST_IOC_MAGIC 0x80
#define MSM_BUS_TEST_REG_CL _IOWR(MSM_BUS_TEST_IOC_MAGIC, 2, \
struct msm_bus_test_cldata)
#define MSM_BUS_TEST_UNREG_CL _IOWR(MSM_BUS_TEST_IOC_MAGIC, 3, \
struct msm_bus_test_cldata)
#define MSM_BUS_TEST_UPDATE_REQ _IOWR(MSM_BUS_TEST_IOC_MAGIC, 4, \
struct msm_bus_test_update_req_data)
#define MSM_BUS_TEST_GET_CLID _IOWR(MSM_BUS_TEST_IOC_MAGIC, 5, uint32_t)
#define MSM_BUS_TEST_GET_RET _IOWR(MSM_BUS_TEST_IOC_MAGIC, 6, int)
#endif /*__MSM_BUS_TEST__*/
@@ -0,0 +1,79 @@
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
testpath=/data/kernel-tests
#
if [ -d /system/lib/modules/ ]; then
modpath=/system/lib/modules
else
modpath=/data
fi
msm_bus_ioctl=${modpath}/msm_bus_ioctl.ko
msm_bus_test=${testpath}/msm_bus_test
chmod 777 $msm_bus_test
CMD_LINE="$@"
NUM_ARGS=$#
# insert the msm_bus_ioctl.ko
insmod $msm_bus_ioctl
if [ $? -ne 0 ]; then
echo "ERROR: failed to load module $msm_bus_ioctl"
sleep 2
exit 1
else
echo "Inserted msm_bus_ioctl module\n"
fi
# Execute the tests
# Run nominal test case by default if there are no args
if [ $NUM_ARGS -ne 0 ]; then
$msm_bus_test $CMD_LINE
else
echo "Running nominal tests (default)"
$msm_bus_test -n
fi
num_failures=$?
# Check for pass or fail status
if [ $num_failures -ne 0 ]; then
echo "MSM_BUS tests failed ($num_failures)"
rc=1
else
echo "MSM_BUS tests passed"
rc=0
fi
echo "Unloading $MSM_BUS_IOCTL.ko"
rmmod $msm_bus_ioctl
exit $rc
@@ -0,0 +1,31 @@
ifeq ($(call is-vendor-board-platform,QCOM),true)
ifeq ($(TARGET_ARCH),arm)
DLKM_DIR := device/qcom/common/dlkm
LOCAL_PATH := $(call my-dir)
# the dlkm
include $(CLEAR_VARS)
LOCAL_MODULE := msm_ocmem_test_module.ko
LOCAL_MODULE_TAGS := debug
include $(DLKM_DIR)/AndroidKernelModule.mk
# the userspace test program
include $(CLEAR_VARS)
LOCAL_MODULE := ocmem_test
LOCAL_SRC_FILES := ocmem_test.c
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests
include $(BUILD_EXECUTABLE)
# the test script
include $(CLEAR_VARS)
LOCAL_MODULE := ocmem_test.sh
LOCAL_SRC_FILES := ocmem_test.sh
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests
include $(BUILD_PREBUILT)
endif
endif
@@ -0,0 +1 @@
obj-m := msm_ocmem_test_module.o
@@ -0,0 +1,27 @@
ocmemdir = $(prefix)/ocmem
ocmem_PROGRAMS = ocmem_test
ocmem_test_LDADD = -lpthread -lrt
ocmem_SCRIPTS = ocmem_test.sh run.sh
KERNEL_FLAGS ?= ARCH=arm
EXTRA_CFLAGS = -DDEBUG
module = msm_ocmem_test_module.ko
kmake = $(MAKE) $(KERNEL_FLAGS) -C $(KERNEL_DIR) M=$(CURDIR)
$(module):
$(kmake) modules
all-local: $(module)
install-exec-local: $(module)
$(kmake) INSTALL_MOD_PATH=$(DESTDIR)$(prefix)/modules modules_install
# "make distclean" will always run clean-local in this directory,
# regardless of the KERNELMODULES conditional. Therefore, ensure
# KERNEL_DIR exists before running clean. Further, don't fail even
# if there is a problem.
clean-local:
-test ! -d "$(KERNEL_DIR)" || $(kmake) clean
@@ -0,0 +1,35 @@
Test: ocmem_test
Usage steps:
# On android:
adb shell
cd /data/kernel-tests
sh ocmem_test.sh [OPTIONS]
# On kdev
/kernel-test/ocmem/run.sh [OPTIONS]
OPTIONS can be:
-n OR --nominal Nominal test (Run by default)
-a OR --adversarial Adversarial tests
-r OR --repeatability [Number of iterations] Repeatability tests
-v OR --verbose Run with debug messages enabled
Description:
Nominal Test:
1. Invoke all OCMEM APIs used by performance mode clients.
2. Invoke all OCMEM APIs used by low power clients.
Adversarial Tests:
1. Invoke all invalid combinations of OCMEM APIs.
Repeatability Tests:
1. Run nominal and adversarial test cases for number of iterations
specified or a maximum of 10 iterations.
Stress tests:
To be defined.
Targets supported: 8974
@@ -0,0 +1,511 @@
/* Copyright (c) 2012-2013, The Linux Foundation. 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 and
* only 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.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/memory.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <mach/irqs.h>
#include <mach/ocmem.h>
#define OCMEM_KERNEL_TEST_MAGIC 0xc1
#define OCMEM_TEST_TYPE_NOMINAL \
_IO(OCMEM_KERNEL_TEST_MAGIC, 1)
#define OCMEM_TEST_TYPE_ADVERSARIAL \
_IO(OCMEM_KERNEL_TEST_MAGIC, 2)
#define OCMEM_TEST_TYPE_STRESS \
_IO(OCMEM_KERNEL_TEST_MAGIC, 3)
#define OCMEM_TEST_VERBOSE_MODE \
_IO(OCMEM_KERNEL_TEST_MAGIC, 4)
#define OCMEM_TEST_DEBUG_MODE \
_IO(OCMEM_KERNEL_TEST_MAGIC, 5)
#define TEST_OCMEM_CLIENT OCMEM_GRAPHICS
/* "OCMM" */
#define OCMEM_READ_WRITE_MAGIC 0xA110CA7E
#define OCMEM_MAX_SIZE 0x180000
#define OCMEM_BASE_ADDR 0xFEC00000
static int debug_mode;
static int verbose_mode;
static int num_test_cases;
static int num_success;
static unsigned long test_ocmem_client_quota;
#define OCMEM_LOG(msg, args...) do { \
if (verbose_mode) \
pr_info(msg, ##args); \
else \
pr_debug(msg, ##args); \
} while (0)
static inline int ocmem_phys_address(unsigned long addr)
{
if (addr <= OCMEM_MAX_SIZE)
addr += OCMEM_BASE_ADDR;
return addr;
}
static int test_client_notif_handler(struct notifier_block *this,
unsigned long event, void *data)
{
struct ocmem_buf *buff = data;
OCMEM_LOG("ocmem_test: test_client notitification event %lu\n", event);
OCMEM_LOG("Notification buffer buff %p(addr %lx:len %lx)\n",
buff, buff->addr, buff->len);
return NOTIFY_DONE;
}
static struct notifier_block test_client_nb = {
.notifier_call = test_client_notif_handler,
};
#ifdef CONFIG_MSM_OCMEM_NONSECURE
static int ocmem_verify_access(int id, struct ocmem_buf *buffer)
{
unsigned long start;
unsigned long sz = buffer->len;
unsigned i = 0;
unsigned failures = 0;
void *vstart = NULL;
unsigned *ptr = NULL;
start = ocmem_phys_address(buffer->addr);
OCMEM_LOG("io-remapping addr %lx and len %lx\n", start, sz);
vstart = ioremap_nocache(start, sz);
if (!vstart) {
pr_err("ocmem test: ioremap failed\n");
return -ENOMEM;
}
ptr = (unsigned *)vstart;
for (i = 0; i < sz/(sizeof(int)); i++) {
ptr[i] = OCMEM_READ_WRITE_MAGIC;
/* Ensure that the value was written out to OCMEM memory */
mb();
if (ptr[i] != OCMEM_READ_WRITE_MAGIC) {
pr_err("ocmem test: verify access failed for client %d\n",
id);
failures++;
}
}
OCMEM_LOG("read write test for memory range %lx to %lx completed\n",
start, start + sz - 1);
iounmap(vstart);
return failures;
}
#else
static int ocmem_verify_access(int id, struct ocmem_buf *buffer)
{
OCMEM_LOG("Secure mode, skipping read/write verification\n");
return 0;
}
#endif
/*
* Test Case: Single Allocation Test
* Invokes: Synchronous allocation call
* Verifies: A buffer of "size" is allocated when there is no contention
*/
static int ocmem_test_single_alloc(void)
{
struct ocmem_buf *buff = NULL;
unsigned long size = test_ocmem_client_quota;
num_test_cases++;
buff = ocmem_allocate(TEST_OCMEM_CLIENT, test_ocmem_client_quota);
if (!buff || !buff->len)
return -EINVAL;
OCMEM_LOG("ocmem test: single_alloc: buff %p(addr:%lx len:%lx)\n",
buff, buff->addr, buff->len);
if (buff->len != size)
return -EINVAL;
ocmem_verify_access(TEST_OCMEM_CLIENT, buff);
if (ocmem_free(TEST_OCMEM_CLIENT, buff))
return -EINVAL;
OCMEM_LOG("ocmem test: single_alloc succeeded\n");
return 0;
}
/*
* Test Case: Single Allocation No Wait Test
* Invokes: Synchronous no wait allocation call
* Verifies: A buffer of "size" is allocated when there is no contention
*/
static int ocmem_test_single_alloc_nowait(void)
{
struct ocmem_buf *buff = NULL;
unsigned long size = test_ocmem_client_quota;
num_test_cases++;
buff = ocmem_allocate_nowait(TEST_OCMEM_CLIENT, size);
if (!buff || !buff->len)
return -EINVAL;
OCMEM_LOG("ocmem test: single_alloc_nw: buff %p(addr:%lx len:%lx)\n",
buff, buff->addr, buff->len);
if (buff->len != size)
return -EINVAL;
ocmem_verify_access(TEST_OCMEM_CLIENT, buff);
if (ocmem_free(TEST_OCMEM_CLIENT, buff))
return -EINVAL;
OCMEM_LOG("ocmem test: single_alloc_nw succeeded\n");
num_success++;
return 0;
}
/*
* Test Case: Single Allocation Range Test
* Invokes: Range allocation call
* Verifies: A buffer of size "max" is allocated when there is no contention
*/
static int ocmem_test_single_alloc_range(void)
{
struct ocmem_buf *buff = NULL;
void *test_client_hndl = NULL;
unsigned long min = test_ocmem_client_quota / 2;
unsigned long max = test_ocmem_client_quota;
unsigned long step = min;
num_test_cases++;
test_client_hndl = ocmem_notifier_register(TEST_OCMEM_CLIENT, &test_client_nb);
if (!test_client_hndl)
goto notifier_fail;
buff = ocmem_allocate_range(TEST_OCMEM_CLIENT, min, max, step);
if (!buff || !buff->len)
goto test_case_fail;
OCMEM_LOG("ocmem test: single_alloc_range: buff %p(addr:%lx len:%lx)\n",
buff, buff->addr, buff->len);
if (buff->len != max)
goto test_case_fail;
if (ocmem_free(TEST_OCMEM_CLIENT, buff))
goto test_case_fail;
if (ocmem_notifier_unregister(test_client_hndl, &test_client_nb))
return -EINVAL;
num_success++;
OCMEM_LOG("ocmem test: single_alloc_range succeeded\n");
return 0;
test_case_fail:
if (ocmem_notifier_unregister(test_client_hndl, &test_client_nb))
return -EINVAL;
notifier_fail:
return -EINVAL;
}
/*
* Test Case: Single Allocation Non blocking Test
* Invokes: Non blocking allocation call
* Verifies: A buffer of "size" is immediately allocated during no contention
*/
static int ocmem_test_single_alloc_nb(void)
{
struct ocmem_buf *buff = NULL;
void *test_client_hndl;
unsigned long size = test_ocmem_client_quota;
num_test_cases++;
test_client_hndl = ocmem_notifier_register(TEST_OCMEM_CLIENT, &test_client_nb);
if (!test_client_hndl)
goto notifier_fail;
buff = ocmem_allocate_nb(TEST_OCMEM_CLIENT, size);
if (!buff || !buff->len)
goto test_case_fail;
OCMEM_LOG("ocmem test: single_alloc_nb: buff %p(addr: %lx len:%lx)\n",
buff, buff->addr, buff->len);
if (buff->len != size)
goto test_case_fail;
if (ocmem_free(TEST_OCMEM_CLIENT, buff))
goto test_case_fail;
if (ocmem_notifier_unregister(test_client_hndl, &test_client_nb))
return -EINVAL;
num_success++;
OCMEM_LOG("ocmem test: single_alloc_nb succeeded\n");
return 0;
test_case_fail:
if (ocmem_notifier_unregister(test_client_hndl, &test_client_nb))
return -EINVAL;
notifier_fail:
return -EINVAL;
}
static int (*nominal_test_cases[]) (void) = {
ocmem_test_single_alloc,
ocmem_test_single_alloc_nowait,
ocmem_test_single_alloc_nb,
ocmem_test_single_alloc_range,
};
static int msm_ocmem_nominal_test(void)
{
unsigned errors = 0;
int rc = 0;
unsigned i = 0;
OCMEM_LOG("OCMEM test: Nominal test suite invoked\n");
for (i = 0; i < ARRAY_SIZE(nominal_test_cases); i++) {
OCMEM_LOG("Nominal test case %d\n", i);
rc = nominal_test_cases[i]();
if (rc < 0) {
pr_err("ocmem test: nominal: test case %d failed\n", i);
errors++;
/* Bail out on first failure if debug mode is not set */
if (!debug_mode)
return -EINVAL;
}
}
OCMEM_LOG("OCMEM test: Nominal test completed with %d errors\n",
errors);
return errors;
}
/*
* Test Case: Allocation Denied Test
* Invokes: Synchronous allocation call
* Verifies: A subystem that is not allowed OCMEM memory must be denied alloc
*/
static int ocmem_test_alloc_denied(void)
{
struct ocmem_buf *buff = NULL;
unsigned long size = test_ocmem_client_quota;
num_test_cases++;
buff = ocmem_allocate(OCMEM_VOICE, size);
if (buff != NULL)
return -EINVAL;
OCMEM_LOG("ocmem test: alloc_denied: NULL buffer returned\n");
num_success++;
return 0;
}
static int (*adversarial_test_cases[]) (void) = {
ocmem_test_alloc_denied,
};
static int msm_ocmem_adversarial_test(void)
{
unsigned errors = 0;
unsigned i = 0;
int rc = 0;
OCMEM_LOG("OCMEM test: Adversarial test suite invoked\n");
for (i = 0; i < ARRAY_SIZE(adversarial_test_cases); i++) {
OCMEM_LOG("Adversarial test case %d\n", i);
rc = adversarial_test_cases[i]();
if (rc < 0) {
pr_err("ocmem test: adversarial: test case %d failed\n",
i);
errors++;
/* Bail out on first failure if debug mode is not set */
if (!debug_mode)
return -EINVAL;
}
}
OCMEM_LOG("OCMEM test: Adversarial test completed with %d errors\n",
errors);
return errors;
}
static int msm_ocmem_stress_test(void)
{
OCMEM_LOG("OCMEM test: Stress test suite invoked\n");
return 0;
}
static long msm_ocmem_test_ioctl(struct file *file, unsigned cmd,
unsigned long arg)
{
long retval = 0;
int err = 0;
OCMEM_LOG("OCMEM test: ioctl invoked");
/* Verify user space ioctl arguments */
if (_IOC_TYPE(cmd) != OCMEM_KERNEL_TEST_MAGIC) {
pr_err("OCMEM test: Unknown IOCTL type, ignoring\n");
return -ENOTTY;
}
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user *)arg,
_IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void __user *)arg,
_IOC_SIZE(cmd));
if (err)
return -EFAULT;
switch (cmd) {
case OCMEM_TEST_DEBUG_MODE:
if (__get_user(debug_mode, (int __user *)arg))
return -EINVAL;
if (debug_mode) {
pr_info("OCMEM test: Enabling debug mode\n");
pr_info("Continue testing all testcases in case of failure\n");
}
break;
case OCMEM_TEST_VERBOSE_MODE:
if (__get_user(verbose_mode, (int __user *)arg))
return -EINVAL;
if (verbose_mode)
pr_info("OCMEM test: Verbose logging enabled\n");
break;
case OCMEM_TEST_TYPE_NOMINAL:
retval = msm_ocmem_nominal_test();
break;
case OCMEM_TEST_TYPE_ADVERSARIAL:
retval = msm_ocmem_adversarial_test();
break;
case OCMEM_TEST_TYPE_STRESS:
retval = msm_ocmem_stress_test();
break;
default:
pr_err("OCMEM test: Invalid ioctl\n");
retval = -EFAULT;
break;
}
return retval;
}
/*
* Register ourselves as a misc device to be able to test the OCMEM code
* from userspace.
*/
static const struct file_operations msm_ocmem_test_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = msm_ocmem_test_ioctl,
};
static struct miscdevice msm_ocmem_test_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "ocmemtest",
.fops = &msm_ocmem_test_fops,
};
/*
* Module Init.
*/
static int __init ocmem_test_init(void)
{
int ret;
pr_info("OCMEM test: Init\n");
ret = misc_register(&msm_ocmem_test_dev);
if (ret < 0) {
pr_err("OCMEM test: Failed to register device");
return -ENODEV;
}
test_ocmem_client_quota = get_max_quota(TEST_OCMEM_CLIENT);
if (!test_ocmem_client_quota) {
pr_err("Couldn't do get_max_quota for TEST_OCMEM_CLIENT (id: %d)\n",
TEST_OCMEM_CLIENT);
ret = -EIO;
goto fail;
}
pr_info("OCMEM test: Module loaded\n");
ret = 0;
return ret;
fail:
misc_deregister(&msm_ocmem_test_dev);
return ret;
}
/*
* Module Exit.
*/
static void __exit ocmem_test_exit(void)
{
pr_info("OCMEM test: Exit\n");
misc_deregister(&msm_ocmem_test_dev);
pr_info("OCMEM test: Module unloaded\n");
}
module_init(ocmem_test_init);
module_exit(ocmem_test_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Test for MSM On-Chip Memory");
@@ -0,0 +1,286 @@
/*
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <unistd.h>
#define OCMEM_KERNEL_TEST_MAGIC 0xc1
#define OCMEM_TEST_TYPE_NOMINAL \
_IO(OCMEM_KERNEL_TEST_MAGIC, 1)
#define OCMEM_TEST_TYPE_ADVERSARIAL \
_IO(OCMEM_KERNEL_TEST_MAGIC, 2)
#define OCMEM_TEST_TYPE_STRESS \
_IO(OCMEM_KERNEL_TEST_MAGIC, 3)
#define OCMEM_TEST_VERBOSE_MODE \
_IO(OCMEM_KERNEL_TEST_MAGIC, 4)
#define OCMEM_TEST_DEBUG_MODE \
_IO(OCMEM_KERNEL_TEST_MAGIC, 5)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
#define NUM_ITERATIONS (10)
static int ocmem_dev_fd;
static int iterations;
static int verbosity;
#define pr_debug(msg, args...) do { \
if (verbosity) \
printf("\n"msg, ##args);\
} while (0)
#define pr_err(msg, args...) do { \
fprintf(stderr, "\n"msg, ##args);\
} while (0)
enum test_types {
NOMINAL,
ADVERSARIAL,
STRESS,
REPEAT,
};
struct option testopts[] = {
{"Nominal", no_argument, NULL, 'n'},
{"Adversarial", no_argument, NULL, 'a'},
{"Stress", no_argument, NULL, 's'},
{"Repeatability", required_argument, NULL, 'r'},
{"Verbose", no_argument, NULL, 'v'},
{"Help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0},
};
static void usage(int ret)
{
printf("Usage: ocmem_test [OPTIONS] [TEST_TYPE]...\n"
"Runs the kernel mode ocmem tests specified by the TEST_TYPE\n"
"parameter. If no TEST_TYPE is specified, then the nominal\n"
" test is run.\n"
"\n"
"OPTIONS can be:\n"
" -v, --verbose run with debug messages enabled\n"
"\n"
"TEST_TYPE can be:\n"
" -n, --nominal run standard functionality tests\n"
" -a, --adversarial run tests that try to break the\n"
" driver\n"
" -s, --stress run tests that try to maximize the\n"
" capacity of the driver\n"
" -r, --repeatability run specified iterations of both the\n"
" nominal and adversarial tests\n");
exit(ret);
}
static unsigned int parse_command(int argc, char *const argv[])
{
int command;
unsigned ret = 0;
while ((command = getopt_long(argc, argv, "vnashr:", testopts,
NULL)) != -1) {
switch (command) {
case 'v':
verbosity = 1;
break;
case 'n':
ret |= 1 << NOMINAL;
break;
case 'a':
ret |= 1 << ADVERSARIAL;
break;
case 's':
ret |= 1 << STRESS;
break;
case 'r':
ret |= 1 << REPEAT;
if (optarg) {
iterations = atoi(optarg);
if (iterations <= 0)
iterations = NUM_ITERATIONS;
printf("Iterations: %d\n\n", iterations);
} else {
iterations = NUM_ITERATIONS;
printf("Using default iterations: %d\n",
iterations);
}
break;
case 'h':
usage(0);
default:
usage(-1);
}
}
return ret;
}
static int nominal_test(void)
{
int errors = 0;
int ret = 0;
pr_debug("OCMEM nominal test iocl invoked\n");
ret = ioctl(ocmem_dev_fd, OCMEM_TEST_TYPE_NOMINAL);
if (ret == -ENOTTY || ret == -EFAULT || ret == -EINVAL) {
pr_err("Failed to invoke ioctl (errno:%d)\n", ret);
exit(-1);
}
if (ret < 0) {
pr_err("OCMEM nominal test FAILED; failures %d\n", ret);
errors++;
}
return errors;
}
static int stress_test(void)
{
int errors = 0;
int ret = 0;
pr_debug("OCMEM nominal test ioctl invoked\n");
ret = ioctl(ocmem_dev_fd, OCMEM_TEST_TYPE_STRESS);
if (ret == -ENOTTY || ret == -EFAULT || ret == -EINVAL) {
pr_err("Failed to invoke ioctl (errno:%d)\n", ret);
exit(-1);
}
if (ret < 0) {
pr_err("OCMEM stress test FAILED; failures %d\n", ret);
errors++;
}
return errors;
}
static int adversarial_test(void)
{
int errors = 0;
int ret = 0;
pr_debug("OCMEM adversarial test ioctl invoked\n");
ret = ioctl(ocmem_dev_fd, OCMEM_TEST_TYPE_ADVERSARIAL);
if (ret == -ENOTTY || ret == -EFAULT || ret == -EINVAL) {
pr_err("Failed to invoke ioctl (errno:%d)\n", ret);
exit(-1);
}
if (ret < 0) {
pr_err("OCMEM adversarial test FAILED; failures %d\n", ret);
errors++;
}
return errors;
}
static int repeat_test(void)
{
unsigned int i = 0;
int errors = 0;
pr_debug("OCMEM repeat test invoked for %d iterations\n", iterations);
for (i = 0; i < iterations; i++) {
pr_debug("Repeat test iteration %d\n", i);
errors += nominal_test();
errors += stress_test();
}
return errors;
}
static int (*test_func[]) () = {
[NOMINAL] = nominal_test,
[ADVERSARIAL] = adversarial_test,
[STRESS] = stress_test,
[REPEAT] = repeat_test,
};
int main(int argc, char **argv)
{
int rc = -1;
int num_failures = 0;
unsigned int i = 0;
unsigned int test_mask = parse_command(argc, argv);
ocmem_dev_fd = open("/dev/ocmemtest", O_RDWR | O_SYNC);
if (ocmem_dev_fd < 0) {
pr_err("Failed to open OCMEM device\n");
return rc;
}
pr_debug("OCMEM opened ocmem_dev_fd (%d) successfully\n",
ocmem_dev_fd);
if (verbosity) {
if (ioctl(ocmem_dev_fd, OCMEM_TEST_VERBOSE_MODE,
&verbosity) < 0)
pr_err("Failed to set verbose mode in DLKM\n");
}
for (i = 0; i < (int)ARRAY_SIZE(test_func); i++) {
/* Look for the test that was selected */
if (!(test_mask & (1U << i)))
continue;
/* This test was selected, so run it */
rc = test_func[i]();
if (rc) {
pr_err("%s test case FAILED! rc:%d\n",
testopts[i].name, rc);
num_failures += rc;
}
}
if (num_failures)
pr_err("OCMEM: NUMBER OF TESTS FAILED: %d\n", num_failures);
close(ocmem_dev_fd);
pr_debug("OCMEM test exiting with %d failures\n", num_failures);
return -num_failures;
}
@@ -0,0 +1,120 @@
# Copyright (c) 2012, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
chmod 755 ocmem_test
if [ -d /system/lib/modules/ ]; then
modpath=/system/lib/modules
else
modpath=/kernel-tests/modules/lib/modules/$(uname -r)/extra
fi
ocmem_test_mod=${modpath}/msm_ocmem_test_module.ko
ocmem_test_dev_misc=/sys/class/misc/ocmemtest/dev
ocmem_test_dev=/dev/ocmemtest
CMD_LINE="$@"
NUM_ARGS=$#
maybe_make_node()
{
thedev=$1
themisc=$2
[ -e $thedev ] || \
mknod $thedev c $(cut -d: -f1 $themisc) $(cut -d: -f2 $themisc)
}
#Parse the args for valid switches
while [ $# -gt 0 ]; do
case $1 in
-n | --nominal)
shift 1
;;
-a | --adversarial)
shift 1
;;
-r | --repeatability)
shift 1
if [ "$1" -eq "$1" ] ; then
echo "Specified $1 iterations"
shift 1
else
echo "Invalid number of iterations"
exit 1
fi
;;
-s | --stress)
shift 1
;;
-v | --verbose)
shift 1
;;
-h | --help | *)
exit 1
;;
esac
done
# insert the msm_ocmem_test_module if needed
if [ ! -e $ocmem_test_dev_misc ]; then
insmod $ocmem_test_mod
if [ $? -ne 0 ]; then
echo "ERROR: failed to load module $ocmem_test_mod"
exit 1
fi
fi
# create the ocmem test device if it doesn't exist
maybe_make_node $ocmem_test_dev $ocmem_test_dev_misc
# Execute the tests
# Run nominal test case by default if there are no args
if [ $NUM_ARGS -ne 0 ]; then
./ocmem_test $CMD_LINE
else
echo "Running nominal tests (default)"
./ocmem_test -n
fi
num_failures=$?
# Check for pass or fail status
if [ $num_failures -ne 0 ]; then
echo "OCMEM tests failed ($num_failures)"
rc=1
else
echo "OCMEM tests passed"
rc=0
fi
echo "Unloading $MSM_OCMEM_TEST_MODULE.ko"
rmmod $ocmem_test_mod
exit $rc
@@ -0,0 +1,31 @@
#! /bin/sh --
# Copyright (c) 2012, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
cd `dirname $0` && exec ./ocmem_test.sh $@
@@ -0,0 +1,26 @@
BOARD_PLATFORM_LIST := msm8974
BOARD_PLATFORM_LIST += msm8226
BOARD_PLATFORM_LIST += msm8610
ifeq ($(call is-board-platform-in-list,$(BOARD_PLATFORM_LIST)),true)
LOCAL_PATH := $(call my-dir)
# the test script
include $(CLEAR_VARS)
LOCAL_MODULE := stm_test.sh
LOCAL_SRC_FILES := stm_test.sh
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests/coresight/stm-trace-marker
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := run.sh
LOCAL_SRC_FILES := run.sh
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests/coresight/stm-trace-marker
include $(BUILD_PREBUILT)
endif
@@ -0,0 +1,39 @@
STM Testing Documentation
Usage: stm_test.sh [runs] [run-size] [delay] [usb|mem]
Runs the basic stm test.
OPTIONS:
The following options can be used:
- runs: Number of runs to be performed
- run-size: Number of trace_marker entries in each run
- delay: The delay between runs, specified in seconds
- usb/mem: If you want the coresight sink to be usb or etr mem, default is etf
Not specifying any of these will default runs=50, run-size=10 and
delay=0.001s, that is 1ms. Also coresight sink will be etf.
TEST BEHAVIOR:
* Test will use trace_marker to test stm. It will start by enabling STM.
It will then echo an increasing counter to the trace_marker
and will continue doing so depending on the number of runs and
run-size specified, The total entries echoed will be run*run-size.
The echoed text will be visible on the screen
It will then disable the STM and dump the ETF dump to the
/data/ftace/stm_trace.bin file. It will also collect the trace.txt
file from debugfs and dump it under /data/coresight alongwith the
format file.
After obtaining the stm_trace.bin file from the device, the qht
tool can be used to parse it and observe the text echoed to the
trace_marker event.
This parsed data can be compared with the data for the trace_marker
event observed in the trace.txt file previously dumped and should
match that exactly.
TARGETS:
* 8974
NOTE:
* Assumes /data partition exists
+78
View File
@@ -0,0 +1,78 @@
#!/bin/sh --
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
if [ $# -eq 0 ]
then
cd `dirname $0` && exec ./stm_test.sh 10 10 0.001
exit 0
fi
#Parse the args for valid switches
while [ $# -gt 0 ]; do
case $1 in
-n | --nominal)
cd `dirname $0` && exec ./stm_test.sh 10 10 0.001
exit 0
;;
-a | --adversarial)
cd `dirname $0` && exec ./stm_test.sh 50 10 0.001
exit 0
;;
-r | --repeatability)
echo $1
if [[ $# -eq 2 && "$2" -gt 0 ]]; then
echo "Specified $2 iterations"
cnt=0
while [ $cnt -le $2 ]
do
cd `dirname $0` && ./stm_test.sh 10 10 0.001
cnt=$(($cnt+1))
done
exit 0
else
echo "Invalid number of iterations"
exit 1
fi
;;
-s | --stress)
cd `dirname $0` && exec ./stm_test.sh 100 10 0.001
exit 0
;;
-v | --verbose)
cd `dirname $0` && exec ./stm_test.sh 10 10 0.001
exit 0
;;
-h | --help | *)
echo "Usage: ./run.sh -[n][a][r][s]"
exit 1
;;
esac
done
+130
View File
@@ -0,0 +1,130 @@
#! /bin/sh
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
runs=49
sets=10
delay=0.001
if [ $# -gt 4 ]
then
echo "Usage: ./stm-test.sh [runs] [run-size] [delay] [usb|mem]"
echo "Delay is specified in seconds."
echo "To specify smaller delays use fractions. For 1ms, use 0.001"
exit
else
if [ $# -eq 1 ]
then
runs=$(($1-1))
echo 1 > /sys/bus/coresight/devices/coresight-tmc-etf/curr_sink
elif [ $# -eq 2 ]
then
runs=$(($1-1))
sets=$2
echo 1 > /sys/bus/coresight/devices/coresight-tmc-etf/curr_sink
elif [ $# -eq 3 ]
then
runs=$(($1-1))
sets=$2
delay=$3
echo 1 > /sys/bus/coresight/devices/coresight-tmc-etf/curr_sink
elif [ $# -eq 4 ]
then
runs=$(($1-1))
sets=$2
delay=$3
if [ $4 = "usb" ] || [ $4 = "mem" ]
then
echo $4 > /sys/bus/coresight/devices/coresight-tmc-etr/out_mode
echo 1 > /sys/bus/coresight/devices/coresight-tmc-etr/curr_sink
else
echo 1 > /sys/bus/coresight/devices/coresight-tmc-etf/curr_sink
fi
fi
fi
echo "STM TEST"
# Mount debugfs
mount -t debugfs nodev /sys/kernel/debug
# create output directory
if [ ! -d "/data" ]
then
mkdir /data
fi
if [ ! -d "/data/coresight" ]
then
mkdir /data/coresight
fi
# Enable stm
echo 1 > /sys/bus/coresight/devices/coresight-stm/enable
# Insert an text marker to indicate start of current test
echo "Starting trace" > /sys/kernel/debug/tracing/trace_marker
# 'X' Sets of 'Y' events with delay
for i in $(seq 0 $runs)
do
echo "Run $(($i+1)): Generating $sets events and sleeping for $delay sec"
for j in $(seq 1 $sets)
do
echo "Event $(($i*$sets+$j))" > /sys/kernel/debug/tracing/trace_marker
done
sleep $delay
done
# Again insert text marker to indicate end of test
echo "Stopping trace" > /sys/kernel/debug/tracing/trace_marker
# Disable stm
echo 0 > /sys/bus/coresight/devices/coresight-stm/enable
# dump trace from etf
if [ $# -eq 4 ]
then
if [ $4 == "mem" ]
then
cat /dev/coresight-tmc-etr > /data/coresight/stm_trace.bin
elif [ $4 != "usb" ]
then
cat /dev/coresight-tmc-etf > /data/coresight/stm_trace.bin
fi
else
cat /dev/coresight-tmc-etf > /data/coresight/stm_trace.bin
fi
cat /sys/kernel/debug/tracing/trace > /data/coresight/trace.txt
# Get format file
cat /sys/kernel/debug/tracing/events/*/*/format > /data/coresight/formats.txt
echo "TEST COMPLETE"
exit 0
@@ -0,0 +1,14 @@
ifeq ($(call is-board-platform,msm8960),true)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_COPY_HEADERS_TO := kernel-tests/sps
LOCAL_COPY_HEADERS := msm_sps_test.h
include $(BUILD_COPY_HEADERS)
LOCAL_MODULE := msm_sps_test_module.ko
LOCAL_MODULE_TAGS := eng
include $(TOP)/device/qcom/common/dlkm/AndroidKernelModule.mk
endif
@@ -0,0 +1 @@
obj-m := msm_sps_test_module.o
@@ -0,0 +1,26 @@
KERNEL_FLAGS ?= ARCH=arm
EXTRA_CFLAGS = -DDEBUG
module = msm_sps_test_module.ko
kmake = $(MAKE) $(KERNEL_FLAGS) -C $(KERNEL_DIR) M=$(CURDIR)
$(module):
$(kmake) modules
all-local: $(module)
install-exec-local: $(module)
$(kmake) INSTALL_MOD_PATH=$(DESTDIR)$(prefix)/modules modules_install
# "make distclean" will always run clean-local in this directory,
# regardless of the KERNELMODULES conditional. Therefore, ensure
# KERNEL_DIR exists before running clean. Further, don't fail even
# if there is a problem.
clean-local:
-test ! -d "$(KERNEL_DIR)" || $(kmake) clean
spsdir = $(prefix)/sps
include_HEADERS = msm_sps_test.h
@@ -0,0 +1,9 @@
#include <linux/ioctl.h>
#define MSM_SPS_TEST_IOC_MAGIC 0xBB
/* Specify the test type */
#define MSM_SPS_TEST_TYPE _IOW(MSM_SPS_TEST_IOC_MAGIC, 1, int)
/* Continue testing all testcases in case of failure */
#define MSM_SPS_TEST_IGNORE_FAILURE _IOW(MSM_SPS_TEST_IOC_MAGIC, 2, int)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,19 @@
AM_CFLAGS = -Werror -g \
-I.
ACLOCAL_AMFLAGS = -I m4
v4l2overlaydir = $(prefix)/v4l2overlay
v4l2overlay_PROGRAMS = v4l2overlay
v4l2overlay_SOURCES = v4l2overlay.c
v4l2overlay_LDADD = ./libv4l2ops.la
lib_LTLIBRARIES = libv4l2ops.la
libv4l2ops_la_SOURCES = v4l2ops.c
pixmapsdir = $(datadir)/pixmaps
pixmaps_DATA = yuv420.raw rgb565.raw
dist_v4l2overlay_SCRIPTS = run.sh
dist_v4l2overlay_DATA = README.txt
@@ -0,0 +1,49 @@
=============================================
V4L2 video overlay test application
=============================================
Test: v4l2overlay test
Usage steps:
adb shell
cd /usr/kernel-tests/v4l2overlay/
./v4l2overlay
OPTIONS can be:
-n OR --nominal Nominal test
-a OR --adversarial Adversarial test
-r OR --repeatability Repeatability test
-s OR --stress Stress test
-v OR --verbose Run with debug messages enabled
-u OR --usage Show usage
-t OR --test Test option
Description:
Nominal Test:
1. Run SIMPLE_OVERLAY test.
Adversarial Tests:
To be defined.
Repeatability Tests:
1. Run SIMPLE_OVERLAY, ROT_0, ROT_90, ROT_180, ROT_270, HFLIP, VFLIP and SCALE
tests.
Stress tests:
To be defined.
Test options:
-t SIMPLE_OVERLAY -- Display image
ROT_0 -- Rotate image by 0 degree
ROT_90 -- Rotate image by 90 degree
ROT_180 -- Rotate image by 270 degree
ROT_270 -- Rotate image by 270 degree
HFLIP -- Horizontally flip image
VFLIP -- Vertically flip image
SCALE -- Scale image
V4L2_MEMORY_USERPTR_TEST -- Display image using user pointer memory
ALL -- Run all the above test
Targets supported:7x27A, 8x55
File diff suppressed because one or more lines are too long
@@ -0,0 +1,31 @@
#!/bin/sh --
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
cd `dirname $0` && exec ./v4l2overlay -v -n
@@ -0,0 +1,556 @@
/*
-----------------------------------------------------------------------------
Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of The Linux Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "v4l2ops.h"
static int _v4l2_pushy_ioctl(int fd, int cmd, void *data)
{
int num_attempts = 0;
int ret;
do {
ret = ioctl(fd, cmd, data);
if(ret == 0 || (errno != EINTR && errno != EAGAIN))
break;
} while (++num_attempts < 100);
return ret;
}
static int _v4l2_querycap(int fd, int capabilities)
{
int ret;
struct v4l2_capability cap;
memset(&cap, 0, sizeof(struct v4l2_capability));
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (ret < 0) {
printf ("VIDIOC_QUERYCAP failed\n");
return ret;
}
if (~cap.capabilities & capabilities)
return -1;
return 0;
}
static int _v4l2_cropcap(int fd, enum v4l2_buf_type type,
struct v4l2_rect *crop)
{
int ret;
struct v4l2_cropcap cropcap;
memset(&cropcap, 0, sizeof(struct v4l2_cropcap));
cropcap.type = type;
ret = ioctl(fd, VIDIOC_CROPCAP, &cropcap);
if (ret < 0) {
printf ("VIDIOC_CROPCAP failed\n");
return ret;
}
if ((crop->left < cropcap.bounds.left) &&
(crop->top < cropcap.bounds.top) &&
(crop->width > cropcap.bounds.width) &&
(crop->height > cropcap.bounds.height)) {
printf ("(%d,%d %dx%d) is out of bound(%d,%d %dx%d)\n",
crop->left, crop->top, crop->width, crop->height,
cropcap.bounds.left, cropcap.bounds.top,
cropcap.bounds.width, cropcap.bounds.height);
return -1;
}
return ret;
}
static int _v4l2_g_fmt(int fd, struct v4l2_format *format)
{
int ret = ioctl(fd, VIDIOC_G_FMT, format);
if (ret < 0) {
printf ("VIDIOC_G_FMT failed\n");
return ret;
}
return 0;
}
static int _v4l2_s_fmt(int fd, struct v4l2_format *format)
{
int ret = ioctl(fd, VIDIOC_S_FMT, format);
if (ret < 0) {
printf ("VIDIOC_S_FMT failed\n");
return ret;
}
return 0;
}
static int _v4l2_g_fbuf(int fd, struct v4l2_framebuffer *frame)
{
int ret = ioctl(fd, VIDIOC_G_FBUF, frame);
if (ret < 0) {
printf ("VIDIOC_G_FBUF failed\n");
return ret;
}
return 0;
}
static int _v4l2_s_fbuf(int fd, struct v4l2_framebuffer *frame)
{
int ret = ioctl(fd, VIDIOC_S_FBUF, frame);
if (ret < 0) {
printf ("VIDIOC_S_FBUF failed\n");
}
return ret;
}
static int _v4l2_s_crop(int fd, struct v4l2_crop *crop)
{
int ret = ioctl(fd, VIDIOC_S_CROP, crop);
if (ret < 0) {
printf ("VIDIOC_S_CROP failed\n");
}
return ret;
}
static int _v4l2_g_ctrl(int fd, struct v4l2_control *ctrl)
{
int ret = ioctl(fd, VIDIOC_G_CTRL, ctrl);
if (ret < 0) {
printf ("VIDIOC_G_CTRL failed\n");
}
return ret;
}
static int _v4l2_s_ctrl(int fd, struct v4l2_control *ctrl)
{
int ret = ioctl(fd, VIDIOC_S_CTRL, ctrl);
if (ret < 0) {
printf ("VIDIOC_S_CTRL failed\n");
}
return ret;
}
static int _v4l2_streamon(int fd, enum v4l2_buf_type type)
{
int ret = _v4l2_pushy_ioctl(fd, VIDIOC_STREAMON, &type);
if (ret < 0) {
printf ("VIDIOC_STREAMON failed\n");
}
return ret;
}
static int _v4l2_streamoff(int fd, enum v4l2_buf_type type)
{
int ret = _v4l2_pushy_ioctl(fd, VIDIOC_STREAMOFF, &type);
if (ret < 0) {
printf ("VIDIOC_STREAMOFF failed \n");
return ret;
}
return ret;
}
static int _v4l2_reqbuf(int fd, struct v4l2_requestbuffers *req)
{
int ret = _v4l2_pushy_ioctl(fd, VIDIOC_REQBUFS, req);
if (ret < 0) {
printf ("VIDIOC_REQBUFS failed\n");
}
return ret;
}
static int _v4l2_querybuf (int fd, struct v4l2_buffer *set_buf)
{
int ret = _v4l2_pushy_ioctl(fd, VIDIOC_QUERYBUF, set_buf);
if (ret < 0) {
printf ("VIDIOC_QUERYBUF failed\n");
}
return ret;
}
static int _v4l2_queue(int fd, struct v4l2_buffer *buf)
{
int ret = _v4l2_pushy_ioctl(fd, VIDIOC_QBUF, buf);
if (ret < 0) {
printf ("VIDIOC_QBUF failed\n");
}
return ret;
}
static int _v4l2_dequeue(int fd, struct v4l2_buffer *buf)
{
int ret = _v4l2_pushy_ioctl(fd, VIDIOC_DQBUF, buf);
if (ret < 0) {
printf ("VIDIOC_DQBUF failed\n");
}
return ret;
}
int v4l2_set_src(int fd, int width, int height,
int crop_x, int crop_y, int crop_w, int crop_h,
unsigned int pixelformat)
{
int capabilities;
int ret;
struct v4l2_format format;
struct v4l2_crop crop;
memset(&format, 0, sizeof(struct v4l2_format));
memset(&crop, 0, sizeof(struct v4l2_crop));
printf ("SetSrc : image(%dx%d) crop(%d,%d %dx%d) pixfmt(0x%08x) \n",
width, height,
crop_x, crop_y, crop_w, crop_h,
pixelformat);
/* check if capabilities is valid */
capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
ret = _v4l2_querycap(fd, capabilities);
if (ret < 0)
return ret;
/* set the size and format of SRC */
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
ret = _v4l2_g_fmt (fd, &format);
if (ret < 0)
return ret;
format.fmt.pix.width = width;
format.fmt.pix.height = height;
format.fmt.pix.pixelformat = pixelformat;
format.fmt.pix.field = V4L2_FIELD_NONE;
ret = _v4l2_s_fmt (fd, &format);
if (ret < 0) {
return ret;
}
/* set the crop area of SRC */
crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
crop.c.left = crop_x;
crop.c.top = crop_y;
crop.c.width = crop_w;
crop.c.height = crop_h;
ret = _v4l2_cropcap (fd, crop.type, &crop.c);
if (ret < 0)
return ret;
ret = _v4l2_s_crop (fd, &crop);
if (ret < 0)
return ret;
return 0;
}
int v4l2_set_dst(int fd,
int dst_x, int dst_y, int dst_w, int dst_h, void *addr)
{
struct v4l2_format format;
struct v4l2_framebuffer fbuf;
int ret;
memset(&format, 0, sizeof(struct v4l2_format));
memset(&fbuf, 0, sizeof(struct v4l2_framebuffer));
printf("SetDst : dst(%d,%d %dx%d) \n", dst_x, dst_y, dst_w, dst_h);
/* set the size and format of DST */
ret = _v4l2_g_fbuf(fd, &fbuf);
if (ret < 0)
return ret;
if (addr != NULL)
/* set the output buffer */
fbuf.base = addr;
fbuf.fmt.width = dst_w;
fbuf.fmt.height = dst_h;
fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB32;
ret = _v4l2_s_fbuf(fd, &fbuf);
if (ret < 0)
return ret;
/* set the size of WIN */
format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
ret = _v4l2_g_fmt(fd, &format);
if (ret < 0)
return ret;
format.fmt.win.w.left = dst_x;
format.fmt.win.w.top = dst_y;
format.fmt.win.w.width = dst_w;
format.fmt.win.w.height = dst_h;
ret = !_v4l2_s_fmt(fd, &format);
if (ret < 0)
return ret;
return 0;
}
int v4l2_set_buffer (int fd,
enum v4l2_memory memory,
int num_buf,
struct mem_buffer **mem_buf)
{
struct v4l2_requestbuffers req;
int ret;
memset(&req, 0, sizeof(struct v4l2_requestbuffers));
printf ("SetBuffer : memory(%d) num_buf(%d) mem_buf(%p)\n",
memory, num_buf, mem_buf);
req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
req.count = num_buf;
req.memory = memory;
ret = _v4l2_reqbuf (fd, &req);
if (ret < 0)
return ret;
if (memory == V4L2_MEMORY_MMAP && mem_buf)
{
struct mem_buffer *out_buf;
int i;
out_buf = calloc(num_buf, sizeof(struct mem_buffer));
if (!out_buf)
return -1;
for (i = 0; i < num_buf; i++)
{
struct v4l2_buffer buffer;
memset(&buffer, 0, sizeof(struct v4l2_buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
buffer.index = i;
buffer.memory = V4L2_MEMORY_MMAP;
ret = _v4l2_querybuf (fd, &buffer);
if (ret < 0) {
free(out_buf);
return ret;
}
out_buf[i].index = buffer.index;
out_buf[i].size = buffer.length;
out_buf[i].buf = (void*)mmap (NULL, buffer.length,
PROT_READ | PROT_WRITE , \
MAP_SHARED , fd, buffer.m.offset);
if (out_buf[i].buf == MAP_FAILED)
{
printf ("mmap failed. index(%d)\n", i);
free(out_buf);
return -1;
}
}
*mem_buf = out_buf;
}
return 0;
}
int v4l2_clear_buffer(int fd,
enum v4l2_memory memory,
int num_buf,
struct mem_buffer *mem_buf)
{
int ret;
/*
* The = {0} syntax gives warnings on gcc version in OE,
* hence the memset
*/
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(struct v4l2_requestbuffers));
printf ("ClearBuffer : memory(%d) num_buf(%d) mem_buf(%p)\n", memory,
num_buf, mem_buf);
if (memory == V4L2_MEMORY_MMAP && mem_buf)
{
int i;
for (i = 0; i < num_buf; i++)
if (mem_buf[i].buf)
if (munmap(mem_buf[i].buf, mem_buf[i].size)
== -1)
printf("Failed to unmap v4l2 buffer at"
"index %d\n", i);
free(mem_buf);
}
req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
req.count = 0;
req.memory = memory;
ret = _v4l2_reqbuf (fd, &req);
if (ret < 0)
return ret;
return 0;
}
int v4l2_set_rotation(int fd, int rotation)
{
int ret;
struct v4l2_control ctrl;
if(rotation == -1)
return 0;
memset(&ctrl, 0, sizeof(struct v4l2_control));
/* set the rotation value */
ctrl.id = V4L2_CID_ROTATE;
ret = _v4l2_g_ctrl (fd, &ctrl);
if (ret < 0)
return ret;
ctrl.value = rotation;
ret = _v4l2_s_ctrl (fd, &ctrl);
if (ret < 0)
return ret;
return 0;
}
int v4l2_set_flip(int fd, int hflip, int vflip)
{
int ret;
struct v4l2_control ctrl;
if(hflip == 0 && vflip == 0)
return 0;
memset(&ctrl, 0, sizeof(struct v4l2_control));
/* set the hflip value */
ctrl.id = V4L2_CID_HFLIP;
ret = _v4l2_g_ctrl (fd, &ctrl);
if (ret < 0)
return ret;
ctrl.value = hflip;
ret = _v4l2_s_ctrl (fd, &ctrl);
if (ret < 0)
return ret;
/* set the vflip value */
ctrl.id = V4L2_CID_VFLIP;
ret = _v4l2_g_ctrl (fd, &ctrl);
if (ret < 0)
return ret;
ctrl.value = vflip;
ret = _v4l2_s_ctrl (fd, &ctrl);
if (ret < 0)
return ret;
return 0;
}
int v4l2_stream_on(int fd)
{
int ret;
ret = _v4l2_streamon (fd, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (ret < 0)
return ret;
return 0;
}
int v4l2_stream_off(int fd)
{
int ret;
ret = _v4l2_streamoff (fd, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (ret < 0)
return ret;
return 0;
}
int v4l2_dequeue(int fd, enum v4l2_memory memory, int *index)
{
int ret;
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(struct v4l2_buffer));
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
buf.memory = memory;
ret = _v4l2_dequeue (fd, &buf);
if (ret < 0)
return ret;
*index = buf.index;
return 0;
}
int v4l2_queue(int fd, int index, enum v4l2_memory memory, __u32 bytes)
{
int ret, i;
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(struct v4l2_buffer));
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
buf.index = index;
buf.memory = memory;
buf.bytesused = bytes;
if (memory == V4L2_MEMORY_USERPTR) {
buf.m.userptr = (unsigned long) userptr;
buf.length = bytes;
}
ret = _v4l2_queue (fd, &buf);
if (ret < 0)
return ret;
return 0;
}
@@ -0,0 +1,103 @@
/*
-----------------------------------------------------------------------------
Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of The Linux Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
#ifndef __V4L2_H__
#define __V4L2_H__
#include <linux/videodev2.h>
#include <linux/ion.h>
struct mem_buffer
{
int index;
int size;
void *buf;
};
struct v4l2_overlay_userptr_buffer {
unsigned int base[3];//base address of plane or frame
size_t offset[3];//offset of plane or frame in multi buffer use case
};
struct v4l2_overlay_userptr_buffer *userptr;
/* ION: start */
#define MEM_NAME_STR_LEN (25)
#define ION_NAME_STR "/dev/ion"
#define ION_NAME_STR_LEN sizeof(ION_NAME_STR)
#define ION_NUM_DEFAULT 0
#define MAX_PLANE 3
struct memDev {
int fd;
int mem_fd;
char mem_name[MEM_NAME_STR_LEN];
int mem_page_size;
int mem_size;
unsigned char *mem_buf;
};
struct memDev * MEM[MAX_PLANE];
struct memDev * ION;
struct memDev ion[MAX_PLANE];
struct ion_handle_data handle_data[MAX_PLANE];
// MEM functions
int chooseMEMDev(void);
int openMEMDev(void);
int allocMEM(unsigned int, unsigned int);
void free_buffer(unsigned int);
void close_ion_device(void);
/* ION: end */
int v4l2_set_src (int fd,
int width, int height,
int crop_x, int crop_y, int crop_w, int crop_h,
unsigned int pixelformat);
int v4l2_set_dst (int fd,
int dst_x, int dst_y, int dst_w, int dst_h,
void *addr);
int v4l2_set_buffer (int fd,
enum v4l2_memory memory,
int num_buf,
struct mem_buffer **mem_buf);
int v4l2_clear_buffer (int fd,
enum v4l2_memory memory,
int num_buf,
struct mem_buffer *mem_buf);
int v4l2_set_rotation (int fd, int rotation);
int v4l2_set_flip (int fd, int hflip, int vflip);
int v4l2_stream_on (int fd);
int v4l2_stream_off (int fd);
int v4l2_dequeue (int fd, enum v4l2_memory memory, int *index);
int v4l2_queue (int fd, int index, enum v4l2_memory memory, __u32 bytes);
#endif //__V4L2_H__
@@ -0,0 +1,961 @@
/*
-----------------------------------------------------------------------------
Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of The Linux Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
/******************************************************************************
@file v4l2overlay.c
@brief This file contains test code to verify functionalities of v4l2overlay
DESCRIPTION
v4l2overlay is display v4l2 test program. It executes specific v4l2 overlay
ioctls as well as the standard linux and msm fb ioctls.
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/fb.h>
#include <linux/stddef.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "v4l2ops.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
struct Rect {
int x;
int y;
int w;
int h;
};
enum device {
INVALID,
MSM8x55,
MSM7x27A,
};
/* Which platform are we running on */
struct platform_parameters {
const char *platform_name;
enum device device_name;
};
/* Fixed image parameters, depend on platform */
struct image_parameters {
const char *image_file[3];//for multi-plane use case only on user ptr
unsigned int num_plane;//for multi-plane use case only on user ptr
unsigned int pixelformat;
struct Rect dimensions;
struct Rect default_crop;
};
/* Variable test parameters */
struct test_parameters {
struct Rect crop;
struct Rect destination;
int buf_count;
enum v4l2_memory memory;
int rotation;
int hflip;
int vflip;
int run;
};
/* ION API's: start */
int chooseMEMDev()
{
ION = &(ion[ION_NUM_DEFAULT]);
strcpy(ION->mem_name, ION_NAME_STR);
return 0;
}
int openMEMDev()
{
int i = 0;
ION->fd = open(ION->mem_name, O_RDWR|O_DSYNC);
if (ION->fd < 0) {
printf("ERROR: Can't open ion %s\n", ION->mem_name);
return -1;
}
else
printf("[%s(%d)]: %s opened ION successfully!\n",__func__ ,
__LINE__, ION->mem_name);
for (i; i < MAX_PLANE; i++) {
MEM[i] = &ion[i];
MEM[i]->fd = ION->fd;
}
return 0;
}
int allocMEM(unsigned int size, unsigned int i)
{
int result = -1;
struct ion_fd_data fd_data;
struct ion_allocation_data ionAllocData;
fd_data.fd = 0;
// First Allocate MEM
MEM[i]->mem_page_size = sysconf(_SC_PAGESIZE);
MEM[i]->mem_size = size;
MEM[i]->mem_size = (MEM[i]->mem_size + MEM[i]->mem_page_size - 1) &
(~(MEM[i]->mem_page_size - 1));
ionAllocData.len = MEM[i]->mem_size;
ionAllocData.align = sysconf(_SC_PAGESIZE);
ionAllocData.flags =
ION_HEAP(ION_IOMMU_HEAP_ID) |
ION_HEAP(ION_CP_MM_HEAP_ID) |
ION_HEAP(ION_CP_WB_HEAP_ID) |
ION_HEAP(ION_SF_HEAP_ID) |
ION_HEAP(ION_CAMERA_HEAP_ID);
result = ioctl(MEM[i]->fd, ION_IOC_ALLOC, &ionAllocData);
if (result) {
printf("ERROR! MEM_ALLOCATE failed.\n");
free_buffer(i);
return -1;
} else {
fd_data.handle = ionAllocData.handle;
handle_data[i].handle = ionAllocData.handle;
if (ioctl(MEM[i]->fd, ION_IOC_MAP, &fd_data)) {
printf("ERROR! ION_IOC_MAP failed.\n");
free_buffer(i);
return -1;
} else {
MEM[i]->mem_buf = mmap(NULL, MEM[i]->mem_size, PROT_READ |
PROT_WRITE, MAP_SHARED, fd_data.fd, 0);
MEM[i]->mem_fd = fd_data.fd;
if (MEM[i]->mem_buf == MAP_FAILED) {
printf("ERROR: MEM MMAP failed!\n");
free_buffer(i);
return -1;
}
memset(MEM[i]->mem_buf, 0x00, MEM[i]->mem_size);
printf("MEM Allocation successful (%d bytes at %p)\n",
MEM[i]->mem_size, MEM[i]->mem_buf);
}
}
return 0;
}
void free_buffer(unsigned int i)
{
//unmap
if ((MEM[i]->mem_buf !=NULL) && (MEM[i]->mem_buf != MAP_FAILED)){
munmap(MEM[i]->mem_buf, MEM[i]->mem_size);
ioctl(MEM[i]->fd, ION_IOC_FREE, &handle_data[i]);
close(MEM[i]->mem_fd);
}
}
void close_ion_device()
{
if (ION->fd >= 0)
close(ION->fd);
}
/* ION API: end*/
static enum device get_hardware_device(void)
{
char line[512];
enum device d = INVALID;
FILE *f = fopen("/proc/cpuinfo", "r");
if (!f) {
perror("open");
return INVALID;
}
while (fgets(line, 512, f) != NULL) {
if (strstr(line, "Hardware")) {
if (strstr(line, "MSM8X55"))
d = MSM8x55;
else if (strstr(line, "MSM7x27a"))
d = MSM7x27A;
else {
d = INVALID;
printf("Could not parse platform, hardware line %s\n",
line);
}
break;
}
}
fclose(f);
if (d == INVALID)
printf("%s: Failed\n", __func__);
return d;
}
static char* read_image(const char *image_path, long *size)
{
char *buffer;
FILE *f = fopen(image_path, "r");
if (!f) {
perror("Could not read image");
return NULL;
}
fseek(f, 0, SEEK_END);
*size = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = malloc(*size + 1);
if (!buffer) {
perror("malloc");
goto end;
}
*size = fread(buffer, 1, *size, f);
end:
fclose(f);
return buffer;
}
static void release_image(char *buffer)
{
free(buffer);
}
/* echo 255 > /sys/class/leds/lcd-backlight/brightness */
static void lights_on(void)
{
FILE *bfd = fopen("/sys/class/leds/lcd-backlight/brightness", "w");
if(!bfd)
perror("warning: could not enable backlight");
else {
fprintf(bfd, "255");
fclose(bfd);
}
}
#define clear_framebuffer(f,v) draw_framebuffer((f),(v), 0)
static void draw_framebuffer(int fb_fd, char *fbp,
struct fb_var_screeninfo* fb_vinfo, int solid_color)
{
int i,j;
char *fb_buf_cur = fbp;
printf("%s: Turning on backlight\n", __func__);
lights_on();
printf("%s: Drawing framebuffer\n", __func__);
for(i=0;i<fb_vinfo->xres;i++) {
for(j=0;j<fb_vinfo->yres;j++) {
/* Assuming ARGB8888, write 4 zero bytes*/
/* TODO: Add RGB565 support for 7x27A */
*fb_buf_cur++ = 0x0;
*fb_buf_cur++ = solid_color ? 0xFF : 0;
*fb_buf_cur++ = 0x0;
*fb_buf_cur++ = 0x0;
}
}
if(ioctl(fb_fd, FBIOPAN_DISPLAY, fb_vinfo) < 0) {
printf("ERROR: FBIOPAN_DISPLAY failed! line=%d\n", __LINE__);
return;
}
printf("%s: done\n", __func__);
}
static int setup_framebuffer(struct fb_var_screeninfo *fb_vinfo)
{
int fb_fd;
char *fbp;
struct fb_var_screeninfo vinfo;
long screensize;
printf("opening framebuffer device\n");
fb_fd = open("/dev/fb0", O_RDWR);
if (fb_fd < 0) {
perror("Cannot open framebuffer device");
return -1;
}
// Get variable screen information
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo)) {
printf("Error reading variable information.\n");
close(fb_fd);
return -1;
}
// Figure out the size of the screen in bytes
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
// Map the device to memory
fbp = (char *)mmap(NULL, screensize+0x100000, PROT_READ | PROT_WRITE, MAP_SHARED,
fb_fd, 0);
if ((int)fbp == -1) {
printf("Error: failed to map framebuffer device to memory.\n");
close(fb_fd);
return -1;
}
printf("successfully opened framebuffer device, now drawing\n");
draw_framebuffer(fb_fd, fbp, &vinfo, 0);
munmap(fbp, screensize);
*fb_vinfo = vinfo;
return fb_fd;
}
static void close_framebuffer(int fb_fd)
{
close(fb_fd);
printf("closed framebuffer device\n");
}
int open_v4l2_overlay_device(void)
{
/* Try /dev/video0 to /dev/video5
This could be better, for example
stat() */
int i;
char device_name[16];
int fd;
struct v4l2_capability cap;
for (i = 0;i <= 5;i++) {
sprintf(device_name, "/dev/video%d", i);
fd = open(device_name, O_RDWR);
if(fd < 0) continue;
memset(&cap, 0, sizeof(struct v4l2_capability));
if(0 != ioctl (fd, VIDIOC_QUERYCAP, &cap)) {
close(fd);
continue;
}
if(cap.capabilities & V4L2_CAP_STREAMING
&& cap.capabilities & V4L2_CAP_VIDEO_OUTPUT
&& cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) {
printf("Found V4L2 video overlay device at %s\n", device_name);
printf("Driver: %s\n", cap.driver);
printf("Card: %s\n", cap.card);
return fd;
}
close(fd);
}
printf("%s: Could not find V4L2 overlay device", __func__);
return -1;
}
void close_v4l2_overlay_device(int fd)
{
close(fd);
}
static int runtest(struct platform_parameters *platform,
struct image_parameters *image, struct test_parameters *test)
{
int v4l2_fd;
int fb_fd;
struct fb_var_screeninfo vinfo;
char *img_buffer[3] = {NULL , NULL, NULL};//single input frame or plane
long img_buf_size[3];//frame size or plane size
int err = 0;
struct mem_buffer *mem_buf;
int index = 0, count, i;
int buffers_mapped = 0;
int streaming = 0;
for (i = 0; i < image->num_plane; i++) {
img_buffer[i] = read_image(image->image_file[i],
&img_buf_size[i]);
if(!img_buffer[i]) {
printf("ERROR: Could not read test image %d\n",i);
return -1;
}
}
printf("Opening V4L2 overlay device\n");
v4l2_fd = open_v4l2_overlay_device();
printf("Done\n");
if(v4l2_fd < 0) {
printf("ERROR: No useable V4L2 overlay device found\n");
return -1;
}
chooseMEMDev();
err = openMEMDev();
if (err < 0)
return -1;
fb_fd = setup_framebuffer(&vinfo);
if(fb_fd < 0) {
printf("ERROR: Could not setup framebuffer\n");
err = -1;
goto done;
}
err = v4l2_set_rotation(v4l2_fd, test->rotation);
if (err < 0)
goto done;
err = v4l2_set_flip(v4l2_fd, test->hflip, test->vflip);
if (err < 0)
goto done;
err = v4l2_set_src(v4l2_fd, image->dimensions.w, image->dimensions.h,
test->crop.x, test->crop.y, test->crop.w,
test->crop.h, image->pixelformat);
if (err < 0)
goto done;
err = v4l2_set_dst(v4l2_fd, test->destination.x, test->destination.y,
test->destination.w, test->destination.h, NULL);
if (err < 0)
goto done;
/* set the memory (mmap or userptr), and get a pointer */
/* test->buf_count is the number of buffers we are
requesting */
err = v4l2_set_buffer(v4l2_fd, test->memory, test->buf_count,
&mem_buf);
if (err < 0)
goto done;
if (test->memory == V4L2_MEMORY_USERPTR) {
printf("allocate ION buffer\n");
for (i = 0; i < image->num_plane; i++) {
if (allocMEM(img_buf_size[i] * test->buf_count, i)) {
printf("allocMEM failed! for buffer %d\n",i);
return -1;
}
}
userptr = (struct v4l2_overlay_userptr_buffer *)
malloc(sizeof(struct v4l2_overlay_userptr_buffer));
if (userptr == NULL) {
printf("userptr memory allocation failed\n");
return -1;
}
for (i = 0; i < MAX_PLANE; i++) {
userptr->base[i] = MEM[i]->mem_fd;
}
}
buffers_mapped = 1;
/* streaming on */
err = v4l2_stream_on(v4l2_fd);
if (err < 0)
goto done;
streaming = 1;
for (count = 0;count <= 5;count++) {
/* draw a frame */
int nbytes;
if (test->memory == V4L2_MEMORY_USERPTR) {
for (i = 0; i < image->num_plane; i++) {
memcpy((MEM[i]->mem_buf +
(index * img_buf_size[i])), img_buffer[i],
img_buf_size[i]);
nbytes = img_buf_size[i];
userptr->offset[i] = index * nbytes;
}
} else {
nbytes = (img_buf_size[0] < mem_buf[index].size) ?
img_buf_size[0] : mem_buf[index].size;
memcpy(mem_buf[index].buf, img_buffer[0], nbytes);
}
err = v4l2_queue(v4l2_fd, index, test->memory, nbytes);
if (err < 0)
goto done;
if (platform->device_name == MSM7x27A) {
if (ioctl(fb_fd, FBIOPAN_DISPLAY, &vinfo) < 0)
printf("%s:ERROR: FBIOPAN_DISPLAY failed!\n",
__func__);
}
err = v4l2_dequeue(v4l2_fd, test->memory, &index);
if (err < 0)
goto done;
if (++index >= test->buf_count)
index = 0;
}
done:
if (streaming)
(void)v4l2_stream_off(v4l2_fd);
if(buffers_mapped)
(void)v4l2_clear_buffer(v4l2_fd, test->memory, test->buf_count,
mem_buf);
for (i = 0; i < MAX_PLANE; i++)
free_buffer(i);
close_ion_device();
if (userptr != NULL) {
free(userptr);
userptr = NULL;
}
for (i = 0; i < image->num_plane; i++) {
if (img_buffer[i])
release_image(img_buffer[i]);
}
if (fb_fd > 0)
close_framebuffer(fb_fd);
close_v4l2_overlay_device(v4l2_fd);
return err;
}
enum test_indices {
SIMPLE_OVERLAY,
ROT_0,
ROT_90,
ROT_180,
ROT_270,
HFLIP,
VFLIP,
SCALE,
V4L2_MEMORY_USERPTR_TEST
};
void showUsage(void)
{
printf("usage: TESTS_LIST\n");
printf("TESTS_LIST is one of more of:\n");
printf("SIMPLE_OVERLAY\n");
printf("ROT_0\n");
printf("ROT_90\n");
printf("ROT_180\n");
printf("ROT_270\n");
printf("HFLIP\n");
printf("VFLIP\n");
printf("SCALE\n");
printf("V4L2_MEMORY_USERPTR_TEST\n");
printf("ALL\n");
printf("ALL runs all the test cases\n");
}
static int select_tests(struct test_parameters *active_tests, int argc, char *argv[])
{
int nr_tests = 0;
int i;
int opt;
struct option longOptions[] = {
{ "usage", no_argument, NULL, 'u'},
{ "verbose", no_argument, NULL, 'v'},
{ "nominal", no_argument, NULL, 'n'},
{ "adversarial", no_argument, NULL, 'a'},
{ "repeatability", no_argument, NULL, 'r'},
{ "stress", no_argument, NULL, 's'},
{ "test", required_argument, NULL, 't'},
};
if (argc == 1) {
printf("This program needs arguments....\n\n");
showUsage();
return 1;
}
optind = 0;
while((opt = getopt_long(argc, argv, "uvnarst:", longOptions,
NULL)) != -1) {
switch(opt) {
case 'u':
showUsage();
return 0;
case 'v':
printf("verbose is enabled\n");
break;
case 'n':
active_tests[SIMPLE_OVERLAY].run = 1;
break;
case 'a':
printf("adversarial test not supported \n");
return 0;
case 'r':
active_tests[SIMPLE_OVERLAY].run = 1;
active_tests[ROT_0].run = 1;
active_tests[ROT_90].run = 1;
active_tests[ROT_180].run = 1;
active_tests[ROT_270].run = 1;
active_tests[HFLIP].run = 1;
active_tests[VFLIP].run = 1;
active_tests[SCALE].run = 1;
break;
case 's':
printf("stress test not supported currently\n");
return 0;
case 't':
if (!strcmp(optarg, "SIMPLE_OVERLAY"))
active_tests[SIMPLE_OVERLAY].run = 1;
else if (!strcmp(optarg, "ROT_0"))
active_tests[ROT_0].run = 1;
else if (!strcmp(optarg, "ROT_90"))
active_tests[ROT_90].run = 1;
else if (!strcmp(optarg, "ROT_180"))
active_tests[ROT_180].run = 1;
else if (!strcmp(optarg, "ROT_270"))
active_tests[ROT_270].run = 1;
else if (!strcmp(optarg, "HFLIP"))
active_tests[HFLIP].run = 1;
else if (!strcmp(optarg, "VFLIP"))
active_tests[VFLIP].run = 1;
else if (!strcmp(optarg, "SCALE"))
active_tests[SCALE].run = 1;
else if (!strcmp(optarg, "V4L2_MEMORY_USERPTR_TEST"))
active_tests[V4L2_MEMORY_USERPTR_TEST].run = 1;
else if (!strcmp(optarg, "ALL")) {
active_tests[SIMPLE_OVERLAY].run = 1;
active_tests[ROT_0].run = 1;
active_tests[ROT_90].run = 1;
active_tests[ROT_180].run = 1;
active_tests[ROT_270].run = 1;
active_tests[HFLIP].run = 1;
active_tests[VFLIP].run = 1;
active_tests[SCALE].run = 1;
} else {
printf("Not a valid test\n");
showUsage();
return 0;
}
break;
default :
printf("Invalid argument: %c\n", opt);
showUsage();
return 0;
}
}
return 1;
}
int main(int argc, char *argv[])
{
struct platform_parameters platform;
struct image_parameters *active_image;
struct test_parameters *active_tests;
int test_nr, pass_cnt = 0, fail_cnt = 0;
int total_tests;
int nr_selected_tests;
int result = -1;
int i;
/*
* multi-plane is supported only for user pointer memory.
* Set num_plane and image_file to be used accordingly.
* In memory map only single plane is supported.
*/
struct image_parameters test_image_8x55 = {
.image_file[0] = "/usr/share/pixmaps/yuv420.raw",
.image_file[1] = "/usr/share/pixmaps/yuv420.raw",
.image_file[2] = "/usr/share/pixmaps/yuv420.raw",
.num_plane = 1,
.pixelformat = V4L2_PIX_FMT_YUV420,
.dimensions = { 0, 0, 176, 144},
.default_crop = { 0, 0, 176, 144}
};
struct image_parameters test_image_7x27A = {
.image_file[0] = "/usr/share/pixmaps/rgb565.raw",
.image_file[1] = "/usr/share/pixmaps/rgb565.raw",
.image_file[2] = "/usr/share/pixmaps/rgb565.raw",
.num_plane = 1,
.pixelformat = V4L2_PIX_FMT_RGB565,
.dimensions = { 0, 0, 320, 240},
.default_crop = { 0, 0, 320, 240}
};
struct test_parameters tests_8x55[] = {
{
.crop = test_image_8x55.default_crop,
.destination = test_image_8x55.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = -1,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_8x55.default_crop,
.destination = test_image_8x55.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = 0,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_8x55.default_crop,
.destination = test_image_8x55.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = 90,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_8x55.default_crop,
.destination = test_image_8x55.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = 180,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_8x55.default_crop,
.destination = test_image_8x55.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = 270,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_8x55.default_crop,
.destination = test_image_8x55.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = -1,
.hflip = 1,
.vflip = 0,
.run = 0
},
{
.crop = test_image_8x55.default_crop,
.destination = test_image_8x55.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = -1,
.hflip = 0,
.vflip = 1,
.run = 0
},
{
.crop = test_image_8x55.default_crop,
.destination = {0, 0, 300, 200},
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = -1,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_8x55.default_crop,
.destination = test_image_8x55.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_USERPTR,
.rotation = -1,
.hflip = 0,
.vflip = 0,
.run = 0
},
};
struct test_parameters tests_7x27A[] = {
{
.crop = test_image_7x27A.default_crop,
.destination = test_image_7x27A.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = -1,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_7x27A.default_crop,
.destination = test_image_7x27A.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = 0,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_7x27A.default_crop,
.destination = test_image_7x27A.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = 90,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_7x27A.default_crop,
.destination = test_image_7x27A.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = 180,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_7x27A.default_crop,
.destination = test_image_7x27A.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = 270,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_7x27A.default_crop,
.destination = test_image_7x27A.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = -1,
.hflip = 1,
.vflip = 0,
.run = 0
},
{
.crop = test_image_7x27A.default_crop,
.destination = test_image_7x27A.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = -1,
.hflip = 0,
.vflip = 1,
.run = 0
},
{
.crop = test_image_7x27A.default_crop,
.destination = {0, 0, 300, 200},
.buf_count = 3,
.memory = V4L2_MEMORY_MMAP,
.rotation = -1,
.hflip = 0,
.vflip = 0,
.run = 0
},
{
.crop = test_image_7x27A.default_crop,
.destination = test_image_7x27A.dimensions,
.buf_count = 3,
.memory = V4L2_MEMORY_USERPTR,
.rotation = -1,
.hflip = 0,
.vflip = 0,
.run = 0
},
};
printf("=============================================\n");
printf(" V4L2 video overlay test application\n");
printf("=============================================\n\n\n");
platform.device_name = get_hardware_device();
if (platform.device_name == INVALID) {
printf("Unable to determine platform, aborting\n");
exit(1);
}
if (platform.device_name == MSM8x55) {
platform.platform_name = "MSM8x55";
active_image = &test_image_8x55;
active_tests = &tests_8x55[0];
total_tests = ARRAY_SIZE(tests_8x55);
} else {
platform.platform_name = "MSM7x27A";
active_image = &test_image_7x27A;
active_tests = &tests_7x27A[0];
total_tests = ARRAY_SIZE(tests_7x27A);
}
nr_selected_tests = select_tests(active_tests, argc, argv);
if (!nr_selected_tests) exit(0);
printf("Detected platform: %s\n\n", platform.platform_name);
printf("Beginning test run, %d total tests\n", nr_selected_tests);
for (i=0, test_nr = 0;i < total_tests;i++) {
struct test_parameters *active_test = active_tests + i;
if (!active_test->run) continue;
printf("Test: %s:%d\n", platform.platform_name, test_nr++);
result = runtest(&platform, active_image, active_test);
if(result != 0) {
fail_cnt++;
printf("Test FAILED.\n");
printf("Failed test parameters:\n");
printf("Source image %s, rect (%d, %d, %d, %d)\n",
active_image->image_file[0], active_image->dimensions.x,
active_image->dimensions.y, active_image->dimensions.w,
active_image->dimensions.h);
printf("Crop rect (%d, %d, %d, %d), dest rect (%d, %d, %d, %d)\n",
active_tests[test_nr].crop.x, active_tests[test_nr].crop.y,
active_tests[test_nr].crop.w, active_tests[test_nr].crop.h,
active_tests[test_nr].destination.x, active_tests[test_nr].destination.y,
active_tests[test_nr].destination.w, active_tests[test_nr].destination.h);
printf("Rotation: %d, hflip: %d, vflip: %d\n",
active_tests[test_nr].rotation, active_tests[test_nr].hflip,
active_tests[test_nr].vflip);
} else {
pass_cnt++;
printf("Test passed.\n");
}
/* Let the last frame be seen on display for some time */
sleep(5);
}
printf("DONE. All tests finished. %d passed, %d failed\n", pass_cnt, fail_cnt);
return 0;
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,26 @@
BOARD_PLATFORM_LIST := msm8974
BOARD_PLATFORM_LIST += msm8226
BOARD_PLATFORM_LIST += msm8610
ifeq ($(call is-board-platform-in-list,$(BOARD_PLATFORM_LIST)),true)
LOCAL_PATH := $(call my-dir)
# the dlkm
include $(CLEAR_VARS)
DLKM_DIR := device/qcom/common/dlkm
LOCAL_MODULE := msm_watchdog_test_module.ko
LOCAL_MODULE_TAGS := debug
include $(DLKM_DIR)/AndroidKernelModule.mk
# the test script
include $(CLEAR_VARS)
LOCAL_MODULE := msm_watchdog_test.sh
LOCAL_SRC_FILES := msm_watchdog_test.sh
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/kernel-tests
include $(BUILD_PREBUILT)
endif
@@ -0,0 +1 @@
obj-m := msm_watchdog_test_module.o
@@ -0,0 +1,24 @@
watchdogdir = $(prefix)/watchdog
KERNEL_FLAGS ?= ARCH=arm
dist_watchdog_SCRIPTS = msm_watchdog_test.sh run.sh
module = msm_watchdog_test_module.ko
kmake = $(MAKE) $(KERNEL_FLAGS) -C $(KERNEL_DIR) M=$(CURDIR)
$(module):
$(kmake) modules
all-local: $(module)
install-exec-local: $(module)
$(kmake) INSTALL_MOD_PATH=$(DESTDIR)$(prefix)/modules modules_install
dist_watchdog_DATA = README.txt
# "make distclean" will always run clean-local in this directory,
# regardless of the KERNELMODULES conditional. Therefore, ensure
# KERNEL_DIR exists before running clean. Further, don't fail even
# if there is a problem.
clean-local:
-test ! -d "$(KERNEL_DIR)" || $(kmake) clean
@@ -0,0 +1,52 @@
Watchdog Testing Documentation
Usage: msm_watchdog_test.sh TEST
Runs the basic watchdog test
TEST can be one of: apps_wdog_bite, sec_wdog_bite,
sec_wdog_scm, apps_wdog_bark
OPTIONS:
The module knows about the following parameters
- apps_wdog_bite
- sec_wdog_bite
- sec_wdog_scm
- apps_wdog_bark
Setting any of these to 1 at insmod time will cause the
corresponding test to be executed. For example, the following will
run the apps watchdog bark test:
# insmod msm_watchdog_test_module.ko apps_wdog_bark=1
However, rather than inserting the module directly and worrying
about supplying the correct parameters, you should use the wrapper
script: msm_watchdog_test.sh.
TEST BEHAVIOR:
* Test will force a watchdog timeout, which will reboot the system.
After obtaining rampdumps from debug mode, the ramdump parser
will produce the following results:
| Test | Outcome |
|----------------+---------------------------------------------------------|
| sec_wdog_scm | No watchdog (FIQ) message should be present. |
| | The CPU context should be dumped as part of |
| | the debug image output. |
|----------------+---------------------------------------------------------|
| sec_wdog_bite | Same as sec_wdog_scm. |
|----------------+---------------------------------------------------------|
| apps_wdog_bark | No watchdog (FIQ) message should be present. |
|----------------+---------------------------------------------------------|
| apps_wdog_bite | Watchdog/FIQ message should be present. The CPU context |
| | should be dumped as part of the debug image output. |
TARGETS:
* 8974
NOTES:
If the script successfully returns and gives you back a shell prompt, the
test failed.
@@ -0,0 +1,56 @@
# Copyright (c) 2012, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of The Linux Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if [ -d /system/lib/modules/ ]; then
modpath=/system/lib/modules
else
modpath=/kernel-tests/modules/lib/modules/$(uname -r)/extra
fi
watchdog_test_mod=${modpath}/msm_watchdog_test_module.ko
case "$1" in
apps_wdog_bite|apps_wdog_bark|sec_wdog_bite|sec_wdog_scm)
thetest="$1"
echo "Running test $thetest"
;;
*)
echo "Unkown test: $1"
echo "Supported tests: apps_wdog_bite apps_wdog_bark sec_wdog_bite sec_wdog_scm"
exit 1
;;
esac
if [ -e $watchdog_test_mod ]; then
insmod $watchdog_test_mod ${thetest}=1
else
echo "watchdog test module not found (${watchdog_test_mod})"
fi
echo "Test failed"
exit 1

Some files were not shown because too many files have changed in this diff Show More